From 436e652835d41e2932ff459c54a507d3b5f714d5 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 18 Aug 2020 06:13:45 +0000 Subject: [PATCH 001/100] Initial SHA structure. Co-authored-by: Bradley Dice --- cpp/include/cudf/types.hpp | 7 +- cpp/src/hash/hash_constants.hpp | 62 ++++++++++++++ cpp/src/hash/hashing.cu | 143 ++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+), 1 deletion(-) diff --git a/cpp/include/cudf/types.hpp b/cpp/include/cudf/types.hpp index e1037efb5c8..1df2eb400bb 100644 --- a/cpp/include/cudf/types.hpp +++ b/cpp/include/cudf/types.hpp @@ -335,7 +335,12 @@ enum class hash_id { HASH_MURMUR3, ///< Murmur3 hash function HASH_MD5, ///< MD5 hash function HASH_SERIAL_MURMUR3, ///< Serial Murmur3 hash function - HASH_SPARK_MURMUR3 ///< Spark Murmur3 hash function + HASH_SPARK_MURMUR3, ///< Spark Murmur3 hash function + HASH_SHA1, + HASH_SHA224, + HASH_SHA256, + HASH_SHA384, + HASH_SHA512 }; /** diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index 0a5a9e0be93..b1732ae1873 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -60,5 +60,67 @@ __device__ __constant__ md5_hash_constants_type md5_hash_constants[64] = { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; + +using sha256_word_type = uint32_t; + +struct sha256_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8]; + uint8_t buffer[64]; +}; + +__device__ __constant__ sha256_word_type sha256_hash_constants[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; +__device__ __constant__ sha256_word_type sha224_initial_hash = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + +__device__ __constant__ sha256_word_type sha256_initial_hash = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +using sha512_word_type = uint64_t; + +struct sha512_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8]; + uint8_t buffer[128]; +}; + +__device__ __constant__ sha512_word_type sha512_hash_constants[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, + 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, + 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, + 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 +}; + +__device__ __constant__ sha512_word_type sha384_initial_hash = { + 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, + 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 +}; + +__device__ __constant__ sha512_word_type sha512_initial_hash = { + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 +}; + } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index a882b33bcdf..207af5bf8d9 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -119,10 +119,153 @@ std::unique_ptr hash(table_view const& input, return serial_murmur_hash3_32(input, seed, stream, mr); case (hash_id::HASH_SPARK_MURMUR3): return serial_murmur_hash3_32(input, seed, stream, mr); + case (hash_id::HASH_SHA1): return sha1(input, stream, mr); + case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); + case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); + case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); + case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); + default: return nullptr; } } +<<<<<<< HEAD +======= +std::unique_ptr md5_hash(table_view const& input, + rmm::mr::device_memory_resource* mr, + cudaStream_t stream) +{ + if (input.num_columns() == 0 || input.num_rows() == 0) { + const string_scalar string_128bit("d41d8cd98f00b204e9orig98ecf8427e"); + auto output = make_column_from_scalar(string_128bit, input.num_rows(), mr, stream); + return output; + } + + CUDF_EXPECTS( + std::all_of(input.begin(), + input.end(), + [](auto col) { + return !is_chrono(col.type()) && + (is_fixed_width(col.type()) || (col.type().id() == type_id::STRING)); + }), + "MD5 unsupported column type"); + + // Result column allocation and creation + auto begin = thrust::make_constant_iterator(32); + auto offsets_column = + cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), mr, stream); + auto offsets_view = offsets_column->view(); + auto d_new_offsets = offsets_view.data(); + + auto chars_column = strings::detail::create_chars_child_column( + input.num_rows(), 0, input.num_rows() * 32, mr, stream); + auto chars_view = chars_column->mutable_view(); + auto d_chars = chars_view.data(); + + rmm::device_buffer null_mask{0, stream, mr}; + + bool const nullable = has_nulls(input); + auto const device_input = table_device_view::create(input, stream); + + // Hash each row, hashing each element sequentially left to right + thrust::for_each( + rmm::exec_policy(stream)->on(stream), + thrust::make_counting_iterator(0), + thrust::make_counting_iterator(input.num_rows()), + [d_chars, device_input = *device_input, has_nulls = nullable] __device__(auto row_index) { + md5_intermediate_data hash_state; + MD5Hash hasher = MD5Hash{}; + for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { + if (device_input.column(col_index).is_valid(row_index)) { + cudf::type_dispatcher(device_input.column(col_index).type(), + hasher, + device_input.column(col_index), + row_index, + &hash_state); + } + } + hasher.finalize(&hash_state, d_chars + (row_index * 32)); + }); + + return make_strings_column(input.num_rows(), + std::move(offsets_column), + std::move(chars_column), + 0, + std::move(null_mask), + stream, + mr); +} + +std::unique_ptr murmur_hash3_32(table_view const& input, + std::vector const& initial_hash, + rmm::mr::device_memory_resource* mr, + cudaStream_t stream) +{ + // TODO this should be UINT32 + auto output = make_numeric_column( + data_type(type_id::INT32), input.num_rows(), mask_state::UNALLOCATED, stream, mr); + + // Return early if there's nothing to hash + if (input.num_columns() == 0 || input.num_rows() == 0) { return output; } + + bool const nullable = has_nulls(input); + auto const device_input = table_device_view::create(input, stream); + auto output_view = output->mutable_view(); + + // Compute the hash value for each row depending on the specified hash function + if (!initial_hash.empty()) { + CUDF_EXPECTS(initial_hash.size() == size_t(input.num_columns()), + "Expected same size of initial hash values as number of columns"); + auto device_initial_hash = rmm::device_vector(initial_hash); + + if (nullable) { + thrust::tabulate(rmm::exec_policy(stream)->on(stream), + output_view.begin(), + output_view.end(), + row_hasher_initial_values( + *device_input, device_initial_hash.data().get())); + } else { + thrust::tabulate(rmm::exec_policy(stream)->on(stream), + output_view.begin(), + output_view.end(), + row_hasher_initial_values( + *device_input, device_initial_hash.data().get())); + } + } else { + if (nullable) { + thrust::tabulate(rmm::exec_policy(stream)->on(stream), + output_view.begin(), + output_view.end(), + row_hasher(*device_input)); + } else { + thrust::tabulate(rmm::exec_policy(stream)->on(stream), + output_view.begin(), + output_view.end(), + row_hasher(*device_input)); + } + } + + return output; +} + +std::unique_ptr sha1(table_view const& input, + rmm::mr::device_memory_resource* mr, + cudaStream_t stream) { +} + +std::unique_ptr sha256_base(table_view const& input, + bool truncate_output, + rmm::mr::device_memory_resource* mr, + cudaStream_t stream) { +} + +std::unique_ptr sha512_base(table_view const& input, + bool truncate_output, + rmm::mr::device_memory_resource* mr, + cudaStream_t stream) { +} + +>>>>>>> 7e5dec8a8d... initial sha structure } // namespace detail std::unique_ptr hash(table_view const& input, From 7c1b66170e70e6681b65f7c954e067ee04403182 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 19 Aug 2020 06:35:31 +0000 Subject: [PATCH 002/100] First pass of SHA1 implementation. Co-authored-by: Bradley Dice --- cpp/CMakeLists.txt | 1 + cpp/include/cudf/detail/hashing.hpp | 17 ++ .../cudf/detail/utilities/hash_functions.cuh | 239 ++++++++++++++++++ cpp/src/hash/hash_constants.hpp | 20 +- cpp/src/hash/hashing.cu | 147 +---------- cpp/src/hash/sha_hash.cu | 121 +++++++++ cpp/tests/hashing/hash_test.cpp | 155 ++++++++++++ 7 files changed, 553 insertions(+), 147 deletions(-) create mode 100644 cpp/src/hash/sha_hash.cu diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 079db9d144b..324f48133ec 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -243,6 +243,7 @@ add_library(cudf src/hash/hashing.cu src/hash/md5_hash.cu src/hash/murmur_hash.cu + src/hash/sha_hash.cu src/interop/dlpack.cpp src/interop/from_arrow.cu src/interop/to_arrow.cu diff --git a/cpp/include/cudf/detail/hashing.hpp b/cpp/include/cudf/detail/hashing.hpp index 83d6be14709..9fdd142240d 100644 --- a/cpp/include/cudf/detail/hashing.hpp +++ b/cpp/include/cudf/detail/hashing.hpp @@ -53,5 +53,22 @@ std::unique_ptr serial_murmur_hash3_32( rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha1_hash( + table_view const& input, + cudaStream_t stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +std::unique_ptr sha256_hash( + table_view const& input, + bool truncate_output, + cudaStream_t stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +std::unique_ptr sha512_hash( + table_view const& input, + bool truncate_output, + cudaStream_t stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + } // namespace detail } // namespace cudf diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 6eab13ae9af..3ca382d4540 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -360,6 +360,245 @@ void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, offsets.element(row_index + 1), hash_state); } + +struct SHA1Hash { + + + CUDA_HOST_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const + { + return (x << r) | (x >> (32 - r)); + } + + /** + * @brief Core SHA1 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + void __device__ hash_step(sha1_intermediate_data* hash_state) const { + uint32_t temp_hash[5]; + thrust::copy_n(thrust::seq, hash_state->hash_value, 5, temp_hash); + // temp_hash[0] = hash_state->hash_value[0]; + // temp_hash[1] = hash_state->hash_value[1]; + // temp_hash[2] = hash_state->hash_value[2]; + // temp_hash[3] = hash_state->hash_value[3]; + // temp_hash[4] = hash_state->hash_value[4]; + + uint32_t words[80]; + for(int i = 0; i < 16; i++) { + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); + // words[i] = buffer_element_as_int; + + words[i] = (buffer_element_as_int << 24) & 0xff000000; + words[i] |= (buffer_element_as_int << 8) & 0xff0000; + words[i] |= (buffer_element_as_int >> 8) & 0xff00; + words[i] |= (buffer_element_as_int >> 24) & 0xff; + } + // std::memcpy(words, hash_state->buffer, 64); + for(int i = 16; i < 80; i++) { + uint32_t temp = words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16]; + words[i] = rotl32(temp, 1); + // words[i] = __funnelshift_l(temp, temp, 1); + } + + // #pragma unroll + for(int i = 0; i < 80; i++) { + uint32_t F; + uint32_t temp; + uint32_t k; + switch(i/20) { + case 0: + // F = (temp_hash[1] & temp_hash[2]) | ((~temp_hash[1]) & temp_hash[3]); + F = ((temp_hash[1] & (temp_hash[2] ^ temp_hash[3])) ^ temp_hash[3]); + k = 0x5a827999; + break; + case 1: + F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + k = 0x6ed9eba1; + break; + case 2: + F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | (temp_hash[2] & temp_hash[3]); + k = 0x8f1bbcdc; + break; + case 3: + F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + k = 0xca62c1d6; + break; + } + temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; + // temp = __funnelshift_l(temp_hash[0], temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; + temp_hash[4] = temp_hash[3]; + temp_hash[3] = temp_hash[2]; + // temp_hash[2] = __funnelshift_l(temp_hash[1], temp_hash[1], 30); + temp_hash[2] = rotl32(temp_hash[1], 30); + temp_hash[1] = temp_hash[0]; + temp_hash[0] = temp; + } + + #pragma unroll + for(int i = 0; i < 5; i++) { + hash_state->hash_value[i] = hash_state->hash_value[i] + temp_hash[i]; + } + } + + /** + * @brief Core SHA1 element processing function + */ + template + void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const { + uint32_t const len = sizeof(TKey); + uint8_t const* data = reinterpret_cast(&key); + hash_state->message_length += len; + + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + if (hash_state->buffer_length + len < sha1_chunk_size) { + thrust::copy_n(thrust::seq, data, len, hash_state->buffer + hash_state->buffer_length); + hash_state->buffer_length += len; + } else { + uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; + + thrust::copy_n(thrust::seq, data, copylen, hash_state->buffer + hash_state->buffer_length); + hash_step(hash_state); + + while (len > sha1_chunk_size + copylen) { + thrust::copy_n(thrust::seq, data + copylen, sha1_chunk_size, hash_state->buffer); + hash_step(hash_state); + copylen += sha1_chunk_size; + } + + thrust::copy_n(thrust::seq, data + copylen, len - copylen, hash_state->buffer); + hash_state->buffer_length = len - copylen; + } + } + + +void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const +{ + auto const full_length = (static_cast(hash_state->message_length)) << 3; + thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); + + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + // 8 bytes for the total message length, appended to the end of the last chunk processed + constexpr int message_length_size = 8; + // 1 byte for the end of the message flag + constexpr int end_of_message_size = 1; + if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { + thrust::fill_n( + thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), + 0x00); + } else { + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - hash_state->buffer_length), + 0x00); + hash_step(hash_state); + + thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); + } + + thrust::copy_n(thrust::seq, + reinterpret_cast(&full_length), + message_length_size, + hash_state->buffer + sha1_chunk_size - message_length_size); + hash_step(hash_state); + // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); + + +#pragma unroll + for (int i = 0; i < 5; ++i){ + + + uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; + flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; + flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; + flipped |= (hash_state->hash_value[i] >> 24) & 0xff; + uint32ToLowercaseHexString(flipped, result_location + (8 * i)); + + // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); + + // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); + // std::memcpy(hash_state->hash_value, &full_length, 8); + // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); + } +} + +template ()>* = nullptr> +void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const +{ + cudf_assert(false && "MD5 Unsupported chrono type column"); +} + +template ()>* = nullptr> +void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const +{ + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); +} + +template ()>* = nullptr> +void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const +{ + T const& key = col.element(row_index); + if (isnan(key)) { + T nan = std::numeric_limits::quiet_NaN(); + process(nan, hash_state); + } else if (key == T{0.0}) { + process(T{0.0}, hash_state); + } else { + process(key, hash_state); + } +} + +template () && !is_floating_point() && + !is_chrono()>* = nullptr> +void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const +{ + process(col.element(row_index), hash_state); +} + +}; + +template <> +void CUDA_DEVICE_CALLABLE SHA1Hash::operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const +{ + string_view key = col.element(row_index); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + thrust::copy_n(thrust::seq, data, len, hash_state->buffer + hash_state->buffer_length); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + thrust::copy_n(thrust::seq, data, copylen, hash_state->buffer + hash_state->buffer_length); + hash_step(hash_state); + + while (len > 64 + copylen) { + thrust::copy_n(thrust::seq, data + copylen, 64, hash_state->buffer); + hash_step(hash_state); + copylen += 64; + } + + thrust::copy_n(thrust::seq, data + copylen, len - copylen, hash_state->buffer); + hash_state->buffer_length = len - copylen; + } +} + } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index b1732ae1873..1156e312400 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -61,6 +61,16 @@ __device__ __constant__ md5_hash_constants_type md5_hash_constants[64] = { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; +using sha1_word_type = uint32_t; + +struct sha1_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + // uint32_t hash_value[5] = {0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210, 0xf0e1d2c3}; + uint8_t buffer[64]; +}; + using sha256_word_type = uint32_t; struct sha256_intermediate_data { @@ -80,9 +90,9 @@ __device__ __constant__ sha256_word_type sha256_hash_constants[64] = { 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -__device__ __constant__ sha256_word_type sha224_initial_hash = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; +__device__ __constant__ sha256_word_type sha224_initial_hash[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; -__device__ __constant__ sha256_word_type sha256_initial_hash = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; +__device__ __constant__ sha256_word_type sha256_initial_hash[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; using sha512_word_type = uint64_t; @@ -109,15 +119,15 @@ __device__ __constant__ sha512_word_type sha512_hash_constants[80] = { 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, - 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -__device__ __constant__ sha512_word_type sha384_initial_hash = { +__device__ __constant__ sha512_word_type sha384_initial_hash[8] = { 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 }; -__device__ __constant__ sha512_word_type sha512_initial_hash = { +__device__ __constant__ sha512_word_type sha512_initial_hash[8] = { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 }; diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index 207af5bf8d9..d4a830f4011 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -119,153 +119,16 @@ std::unique_ptr hash(table_view const& input, return serial_murmur_hash3_32(input, seed, stream, mr); case (hash_id::HASH_SPARK_MURMUR3): return serial_murmur_hash3_32(input, seed, stream, mr); - case (hash_id::HASH_SHA1): return sha1(input, stream, mr); - case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); - case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); - case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); - case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); + case (hash_id::HASH_SHA1): return sha1_hash(input, stream, mr); + // case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); + // case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); + // case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); + // case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); default: return nullptr; } } -<<<<<<< HEAD -======= -std::unique_ptr md5_hash(table_view const& input, - rmm::mr::device_memory_resource* mr, - cudaStream_t stream) -{ - if (input.num_columns() == 0 || input.num_rows() == 0) { - const string_scalar string_128bit("d41d8cd98f00b204e9orig98ecf8427e"); - auto output = make_column_from_scalar(string_128bit, input.num_rows(), mr, stream); - return output; - } - - CUDF_EXPECTS( - std::all_of(input.begin(), - input.end(), - [](auto col) { - return !is_chrono(col.type()) && - (is_fixed_width(col.type()) || (col.type().id() == type_id::STRING)); - }), - "MD5 unsupported column type"); - - // Result column allocation and creation - auto begin = thrust::make_constant_iterator(32); - auto offsets_column = - cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), mr, stream); - auto offsets_view = offsets_column->view(); - auto d_new_offsets = offsets_view.data(); - - auto chars_column = strings::detail::create_chars_child_column( - input.num_rows(), 0, input.num_rows() * 32, mr, stream); - auto chars_view = chars_column->mutable_view(); - auto d_chars = chars_view.data(); - - rmm::device_buffer null_mask{0, stream, mr}; - - bool const nullable = has_nulls(input); - auto const device_input = table_device_view::create(input, stream); - - // Hash each row, hashing each element sequentially left to right - thrust::for_each( - rmm::exec_policy(stream)->on(stream), - thrust::make_counting_iterator(0), - thrust::make_counting_iterator(input.num_rows()), - [d_chars, device_input = *device_input, has_nulls = nullable] __device__(auto row_index) { - md5_intermediate_data hash_state; - MD5Hash hasher = MD5Hash{}; - for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { - if (device_input.column(col_index).is_valid(row_index)) { - cudf::type_dispatcher(device_input.column(col_index).type(), - hasher, - device_input.column(col_index), - row_index, - &hash_state); - } - } - hasher.finalize(&hash_state, d_chars + (row_index * 32)); - }); - - return make_strings_column(input.num_rows(), - std::move(offsets_column), - std::move(chars_column), - 0, - std::move(null_mask), - stream, - mr); -} - -std::unique_ptr murmur_hash3_32(table_view const& input, - std::vector const& initial_hash, - rmm::mr::device_memory_resource* mr, - cudaStream_t stream) -{ - // TODO this should be UINT32 - auto output = make_numeric_column( - data_type(type_id::INT32), input.num_rows(), mask_state::UNALLOCATED, stream, mr); - - // Return early if there's nothing to hash - if (input.num_columns() == 0 || input.num_rows() == 0) { return output; } - - bool const nullable = has_nulls(input); - auto const device_input = table_device_view::create(input, stream); - auto output_view = output->mutable_view(); - - // Compute the hash value for each row depending on the specified hash function - if (!initial_hash.empty()) { - CUDF_EXPECTS(initial_hash.size() == size_t(input.num_columns()), - "Expected same size of initial hash values as number of columns"); - auto device_initial_hash = rmm::device_vector(initial_hash); - - if (nullable) { - thrust::tabulate(rmm::exec_policy(stream)->on(stream), - output_view.begin(), - output_view.end(), - row_hasher_initial_values( - *device_input, device_initial_hash.data().get())); - } else { - thrust::tabulate(rmm::exec_policy(stream)->on(stream), - output_view.begin(), - output_view.end(), - row_hasher_initial_values( - *device_input, device_initial_hash.data().get())); - } - } else { - if (nullable) { - thrust::tabulate(rmm::exec_policy(stream)->on(stream), - output_view.begin(), - output_view.end(), - row_hasher(*device_input)); - } else { - thrust::tabulate(rmm::exec_policy(stream)->on(stream), - output_view.begin(), - output_view.end(), - row_hasher(*device_input)); - } - } - - return output; -} - -std::unique_ptr sha1(table_view const& input, - rmm::mr::device_memory_resource* mr, - cudaStream_t stream) { -} - -std::unique_ptr sha256_base(table_view const& input, - bool truncate_output, - rmm::mr::device_memory_resource* mr, - cudaStream_t stream) { -} - -std::unique_ptr sha512_base(table_view const& input, - bool truncate_output, - rmm::mr::device_memory_resource* mr, - cudaStream_t stream) { -} - ->>>>>>> 7e5dec8a8d... initial sha structure } // namespace detail std::unique_ptr hash(table_view const& input, diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu new file mode 100644 index 00000000000..08f2ca87f98 --- /dev/null +++ b/cpp/src/hash/sha_hash.cu @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2019-2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace cudf { +namespace { + +// SHA supported leaf data type check +bool sha_type_check(data_type dt) +{ + return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); +} + +} // namespace + +namespace detail { + +std::unique_ptr sha1_hash(table_view const& input, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) { + + if (input.num_columns() == 0 || input.num_rows() == 0) { + const string_scalar string_160bit("da39a3ee5e6b4b0d3255bfef95601890afd80709"); + auto output = make_column_from_scalar(string_160bit, input.num_rows(), stream, mr); + return output; + } + + CUDF_EXPECTS( + std::all_of(input.begin(), + input.end(), + [](auto col) { + return sha_type_check(col.type()); + }), + "SHA1 unsupported column type"); + + // Result column allocation and creation + auto begin = thrust::make_constant_iterator(40); + auto offsets_column = + cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), stream, mr); + auto offsets_view = offsets_column->view(); + auto d_new_offsets = offsets_view.data(); + + auto chars_column = strings::detail::create_chars_child_column( + input.num_rows() * 40, stream, mr); + auto chars_view = chars_column->mutable_view(); + auto d_chars = chars_view.data(); + + rmm::device_buffer null_mask{0, stream, mr}; + + bool const nullable = has_nulls(input); + auto const device_input = table_device_view::create(input, stream); + + // Hash each row, hashing each element sequentially left to right + thrust::for_each( + rmm::exec_policy(stream), + thrust::make_counting_iterator(0), + thrust::make_counting_iterator(input.num_rows()), + [d_chars, device_input = *device_input] __device__(auto row_index) { + sha1_intermediate_data hash_state; + SHA1Hash hasher = SHA1Hash{}; + // for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { + // if (device_input.column(col_index).is_valid(row_index)) { + // cudf::type_dispatcher(device_input.column(col_index).type(), + // hasher, + // device_input.column(col_index), + // row_index, + // &hash_state); + // } + // } + hasher.finalize(&hash_state, d_chars + (row_index * 40)); + }); + + return make_strings_column(input.num_rows(), + std::move(offsets_column), + std::move(chars_column), + 0, + std::move(null_mask), + stream, + mr); +} + +std::unique_ptr sha256_hash(table_view const& input, + bool truncate_output, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) { + return nullptr; +} + +std::unique_ptr sha512_hash(table_view const& input, + bool truncate_output, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) { + return nullptr; +} + +} // namespace detail +} // namespace cudf diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index a605fdee6a0..fb929fd6aff 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -714,4 +714,159 @@ TYPED_TEST(MD5HashTestFloatTyped, TestListExtremes) CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view(), verbosity); } + +class SHA1HashTest : public cudf::test::BaseFixture { +}; + +TEST_F(SHA1HashTest, MultiValue) +{ + strings_column_wrapper const strings_col( + {"", + "A 60 character string to test SHA1's message padding algorithm", + "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in the " + "SHA1 hash function. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); + + strings_column_wrapper const sha1_string_results1({"da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + + strings_column_wrapper const sha1_string_results2({"da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col({0, 100, -100, limits::min(), limits::max()}); + + // Different truth values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0}); + + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const sha1_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA1); + auto const sha1_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA1); + EXPECT_EQ(string_input1.num_rows(), sha1_string_output1->size()); + EXPECT_EQ(string_input2.num_rows(), sha1_string_output2->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output1->view(), sha1_string_results1); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output2->view(), sha1_string_results2); + + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const sha1_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); + auto const sha1_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + EXPECT_EQ(input1.num_rows(), sha1_output1->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_output1->view(), sha1_output2->view()); +} + +// TEST_F(SHA1HashTest, MultiValueNulls) +// { +// // Nulls with different values should be equal +// strings_column_wrapper const strings_col1( +// {"", +// "Different but null!", +// "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in the " +// "MD5 hash function. This string needed to be longer.", +// "All work and no play makes Jack a dull boy", +// "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, +// {1, 0, 0, 1, 0}); +// strings_column_wrapper const strings_col2( +// {"", +// "A 60 character string to test MD5's message padding algorithm", +// "Very different... but null", +// "All work and no play makes Jack a dull boy", +// ""}, +// {1, 0, 0, 1, 1}); // empty string is equivalent to null + +// // Nulls with different values should be equal +// using limits = std::numeric_limits; +// fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, +// {1, 0, 0, 1, 1}); +// fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, +// {1, 0, 0, 1, 1}); + +// // Nulls with different values should be equal +// // Different truthy values should be equal +// fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); +// fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + +// auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); +// auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + +// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); +// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + +// EXPECT_EQ(input1.num_rows(), output1->size()); +// expect_columns_equal(output1->view(), output2->view()); +// } + +// template +// class SHA1HashTestTyped : public cudf::test::BaseFixture { +// }; + +// TYPED_TEST_CASE(SHA1HashTestTyped, cudf::test::NumericTypes); + +// TYPED_TEST(SHA1HashTestTyped, Equality) +// { +// fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); +// auto const input = cudf::table_view({col}); + +// // Hash of same input should be equal +// auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA1); +// auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); + +// EXPECT_EQ(input.num_rows(), output1->size()); +// expect_columns_equal(output1->view(), output2->view()); +// } + +// TYPED_TEST(SHA1HashTestTyped, EqualityNulls) +// { +// using T = TypeParam; + +// // Nulls with different values should be equal +// fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); +// fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + +// auto const input1 = cudf::table_view({col1}); +// auto const input2 = cudf::table_view({col2}); + +// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); +// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + +// EXPECT_EQ(input1.num_rows(), output1->size()); +// expect_columns_equal(output1->view(), output2->view()); +// } + +// template +// class SHA1HashTestFloatTyped : public cudf::test::BaseFixture { +// }; + +// TYPED_TEST_CASE(SHA1HashTestFloatTyped, cudf::test::FloatingPointTypes); + +// TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) +// { +// using T = TypeParam; +// T min = std::numeric_limits::min(); +// T max = std::numeric_limits::max(); +// T nan = std::numeric_limits::quiet_NaN(); +// T inf = std::numeric_limits::infinity(); + +// fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); +// fixed_width_column_wrapper const col2( +// {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + +// auto const input1 = cudf::table_view({col1}); +// auto const input2 = cudf::table_view({col2}); + +// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); +// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + +// expect_columns_equal(output1->view(), output2->view(), true); +// } + CUDF_TEST_PROGRAM_MAIN() From aac184b1e682084d7305248809bf10182d70c5d1 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Fri, 3 Sep 2021 15:44:43 -0700 Subject: [PATCH 003/100] Apply clang-format. --- .../cudf/detail/utilities/hash_functions.cuh | 213 +++++++++--------- cpp/src/hash/hash_constants.hpp | 73 +++--- cpp/src/hash/hashing.cu | 11 +- cpp/src/hash/sha_hash.cu | 77 +++---- cpp/tests/hashing/hash_test.cpp | 31 ++- 5 files changed, 205 insertions(+), 200 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 3ca382d4540..cdf13fc8f03 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -362,18 +362,17 @@ void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, } struct SHA1Hash { - - CUDA_HOST_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const { return (x << r) | (x >> (32 - r)); } /** - * @brief Core SHA1 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - void __device__ hash_step(sha1_intermediate_data* hash_state) const { + * @brief Core SHA1 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + void __device__ hash_step(sha1_intermediate_data* hash_state) const + { uint32_t temp_hash[5]; thrust::copy_n(thrust::seq, hash_state->hash_value, 5, temp_hash); // temp_hash[0] = hash_state->hash_value[0]; @@ -383,7 +382,7 @@ struct SHA1Hash { // temp_hash[4] = hash_state->hash_value[4]; uint32_t words[80]; - for(int i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); // words[i] = buffer_element_as_int; @@ -394,18 +393,18 @@ struct SHA1Hash { words[i] |= (buffer_element_as_int >> 24) & 0xff; } // std::memcpy(words, hash_state->buffer, 64); - for(int i = 16; i < 80; i++) { - uint32_t temp = words[i-3] ^ words[i-8] ^ words[i-14] ^ words[i-16]; - words[i] = rotl32(temp, 1); + for (int i = 16; i < 80; i++) { + uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotl32(temp, 1); // words[i] = __funnelshift_l(temp, temp, 1); } - // #pragma unroll - for(int i = 0; i < 80; i++) { + // #pragma unroll + for (int i = 0; i < 80; i++) { uint32_t F; uint32_t temp; uint32_t k; - switch(i/20) { + switch (i / 20) { case 0: // F = (temp_hash[1] & temp_hash[2]) | ((~temp_hash[1]) & temp_hash[3]); F = ((temp_hash[1] & (temp_hash[2] ^ temp_hash[3])) ^ temp_hash[3]); @@ -416,15 +415,16 @@ struct SHA1Hash { k = 0x6ed9eba1; break; case 2: - F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | (temp_hash[2] & temp_hash[3]); + F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | + (temp_hash[2] & temp_hash[3]); k = 0x8f1bbcdc; break; case 3: - F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; k = 0xca62c1d6; break; } - temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; + temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; // temp = __funnelshift_l(temp_hash[0], temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; temp_hash[4] = temp_hash[3]; temp_hash[3] = temp_hash[2]; @@ -434,17 +434,18 @@ struct SHA1Hash { temp_hash[0] = temp; } - #pragma unroll - for(int i = 0; i < 5; i++) { +#pragma unroll + for (int i = 0; i < 5; i++) { hash_state->hash_value[i] = hash_state->hash_value[i] + temp_hash[i]; } } /** - * @brief Core SHA1 element processing function - */ + * @brief Core SHA1 element processing function + */ template - void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const { + void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const + { uint32_t const len = sizeof(TKey); uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; @@ -471,108 +472,102 @@ struct SHA1Hash { } } + void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const + { + auto const full_length = (static_cast(hash_state->message_length)) << 3; + thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); -void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const -{ - auto const full_length = (static_cast(hash_state->message_length)) << 3; - thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - - // 64 bytes for the number of bytes processed in a given step - constexpr int sha1_chunk_size = 64; - // 8 bytes for the total message length, appended to the end of the last chunk processed - constexpr int message_length_size = 8; - // 1 byte for the end of the message flag - constexpr int end_of_message_size = 1; - if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { - thrust::fill_n( - thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), - 0x00); - } else { - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - hash_state->buffer_length), - 0x00); - hash_step(hash_state); - - thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); - } + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + // 8 bytes for the total message length, appended to the end of the last chunk processed + constexpr int message_length_size = 8; + // 1 byte for the end of the message flag + constexpr int end_of_message_size = 1; + if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { + thrust::fill_n( + thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), + 0x00); + } else { + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - hash_state->buffer_length), + 0x00); + hash_step(hash_state); - thrust::copy_n(thrust::seq, - reinterpret_cast(&full_length), - message_length_size, - hash_state->buffer + sha1_chunk_size - message_length_size); - hash_step(hash_state); - // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); + thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); + } + thrust::copy_n(thrust::seq, + reinterpret_cast(&full_length), + message_length_size, + hash_state->buffer + sha1_chunk_size - message_length_size); + hash_step(hash_state); + // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); #pragma unroll - for (int i = 0; i < 5; ++i){ - - - uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; - flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; - flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; - flipped |= (hash_state->hash_value[i] >> 24) & 0xff; - uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - - // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); - - // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); - // std::memcpy(hash_state->hash_value, &full_length, 8); - // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); + for (int i = 0; i < 5; ++i) { + uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; + flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; + flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; + flipped |= (hash_state->hash_value[i] >> 24) & 0xff; + uint32ToLowercaseHexString(flipped, result_location + (8 * i)); + + // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); + + // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); + // std::memcpy(hash_state->hash_value, &full_length, 8); + // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); + } } -} -template ()>* = nullptr> -void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const -{ - cudf_assert(false && "MD5 Unsupported chrono type column"); -} - -template ()>* = nullptr> -void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const -{ - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); -} + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported chrono type column"); + } -template ()>* = nullptr> -void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const -{ - T const& key = col.element(row_index); - if (isnan(key)) { - T nan = std::numeric_limits::quiet_NaN(); - process(nan, hash_state); - } else if (key == T{0.0}) { - process(T{0.0}, hash_state); - } else { - process(key, hash_state); + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); } -} -template () && !is_floating_point() && - !is_chrono()>* = nullptr> -void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const -{ - process(col.element(row_index), hash_state); -} + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + T const& key = col.element(row_index); + if (isnan(key)) { + T nan = std::numeric_limits::quiet_NaN(); + process(nan, hash_state); + } else if (key == T{0.0}) { + process(T{0.0}, hash_state); + } else { + process(key, hash_state); + } + } + template () && !is_floating_point() && + !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + process(col.element(row_index), hash_state); + } }; template <> -void CUDA_DEVICE_CALLABLE SHA1Hash::operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const +void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( + column_device_view col, size_type row_index, sha1_intermediate_data* hash_state) const { string_view key = col.element(row_index); uint32_t const len = static_cast(key.size_bytes()); diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index 1156e312400..dd869b44912 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -66,7 +66,7 @@ using sha1_word_type = uint32_t; struct sha1_intermediate_data { uint64_t message_length = 0; uint32_t buffer_length = 0; - uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; // uint32_t hash_value[5] = {0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210, 0xf0e1d2c3}; uint8_t buffer[64]; }; @@ -88,11 +88,12 @@ __device__ __constant__ sha256_word_type sha256_hash_constants[64] = { 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; -__device__ __constant__ sha256_word_type sha224_initial_hash[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; +__device__ __constant__ sha256_word_type sha224_initial_hash[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; -__device__ __constant__ sha256_word_type sha256_initial_hash[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; +__device__ __constant__ sha256_word_type sha256_initial_hash[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; using sha512_word_type = uint64_t; @@ -104,33 +105,45 @@ struct sha512_intermediate_data { }; __device__ __constant__ sha512_word_type sha512_hash_constants[80] = { - 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, - 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, - 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, - 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, - 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, - 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, - 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, - 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, - 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, - 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, - 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, - 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, - 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, -}; - -__device__ __constant__ sha512_word_type sha384_initial_hash[8] = { - 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, - 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -__device__ __constant__ sha512_word_type sha512_initial_hash[8] = { - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 -}; +__device__ __constant__ sha512_word_type sha384_initial_hash[8] = {0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4}; + +__device__ __constant__ sha512_word_type sha512_initial_hash[8] = {0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179}; } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index d4a830f4011..ce7005c93e6 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -119,11 +119,12 @@ std::unique_ptr hash(table_view const& input, return serial_murmur_hash3_32(input, seed, stream, mr); case (hash_id::HASH_SPARK_MURMUR3): return serial_murmur_hash3_32(input, seed, stream, mr); - case (hash_id::HASH_SHA1): return sha1_hash(input, stream, mr); - // case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); - // case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); - // case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); - // case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); + case (hash_id::HASH_SHA1): + return sha1_hash(input, stream, mr); + // case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); + // case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); + // case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); + // case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); default: return nullptr; } diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 08f2ca87f98..c5c00f7f647 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -40,9 +40,9 @@ bool sha_type_check(data_type dt) namespace detail { std::unique_ptr sha1_hash(table_view const& input, - cudaStream_t stream, - rmm::mr::device_memory_resource* mr) { - + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) +{ if (input.num_columns() == 0 || input.num_rows() == 0) { const string_scalar string_160bit("da39a3ee5e6b4b0d3255bfef95601890afd80709"); auto output = make_column_from_scalar(string_160bit, input.num_rows(), stream, mr); @@ -50,11 +50,7 @@ std::unique_ptr sha1_hash(table_view const& input, } CUDF_EXPECTS( - std::all_of(input.begin(), - input.end(), - [](auto col) { - return sha_type_check(col.type()); - }), + std::all_of(input.begin(), input.end(), [](auto col) { return sha_type_check(col.type()); }), "SHA1 unsupported column type"); // Result column allocation and creation @@ -64,10 +60,9 @@ std::unique_ptr sha1_hash(table_view const& input, auto offsets_view = offsets_column->view(); auto d_new_offsets = offsets_view.data(); - auto chars_column = strings::detail::create_chars_child_column( - input.num_rows() * 40, stream, mr); - auto chars_view = chars_column->mutable_view(); - auto d_chars = chars_view.data(); + auto chars_column = strings::detail::create_chars_child_column(input.num_rows() * 40, stream, mr); + auto chars_view = chars_column->mutable_view(); + auto d_chars = chars_view.data(); rmm::device_buffer null_mask{0, stream, mr}; @@ -75,46 +70,48 @@ std::unique_ptr sha1_hash(table_view const& input, auto const device_input = table_device_view::create(input, stream); // Hash each row, hashing each element sequentially left to right - thrust::for_each( - rmm::exec_policy(stream), - thrust::make_counting_iterator(0), - thrust::make_counting_iterator(input.num_rows()), - [d_chars, device_input = *device_input] __device__(auto row_index) { - sha1_intermediate_data hash_state; - SHA1Hash hasher = SHA1Hash{}; - // for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { - // if (device_input.column(col_index).is_valid(row_index)) { - // cudf::type_dispatcher(device_input.column(col_index).type(), - // hasher, - // device_input.column(col_index), - // row_index, - // &hash_state); - // } - // } - hasher.finalize(&hash_state, d_chars + (row_index * 40)); - }); + thrust::for_each(rmm::exec_policy(stream), + thrust::make_counting_iterator(0), + thrust::make_counting_iterator(input.num_rows()), + [d_chars, device_input = *device_input] __device__(auto row_index) { + sha1_intermediate_data hash_state; + SHA1Hash hasher = SHA1Hash{}; + // for (int col_index = 0; col_index < device_input.num_columns(); col_index++) + // { + // if (device_input.column(col_index).is_valid(row_index)) { + // cudf::type_dispatcher(device_input.column(col_index).type(), + // hasher, + // device_input.column(col_index), + // row_index, + // &hash_state); + // } + // } + hasher.finalize(&hash_state, d_chars + (row_index * 40)); + }); return make_strings_column(input.num_rows(), - std::move(offsets_column), - std::move(chars_column), - 0, - std::move(null_mask), - stream, - mr); + std::move(offsets_column), + std::move(chars_column), + 0, + std::move(null_mask), + stream, + mr); } std::unique_ptr sha256_hash(table_view const& input, bool truncate_output, cudaStream_t stream, - rmm::mr::device_memory_resource* mr) { - return nullptr; + rmm::mr::device_memory_resource* mr) +{ + return nullptr; } std::unique_ptr sha512_hash(table_view const& input, bool truncate_output, cudaStream_t stream, - rmm::mr::device_memory_resource* mr) { - return nullptr; + rmm::mr::device_memory_resource* mr) +{ + return nullptr; } } // namespace detail diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index fb929fd6aff..aa9a8db4f50 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -714,7 +714,6 @@ TYPED_TEST(MD5HashTestFloatTyped, TestListExtremes) CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view(), verbosity); } - class SHA1HashTest : public cudf::test::BaseFixture { }; @@ -729,16 +728,16 @@ TEST_F(SHA1HashTest, MultiValue) "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); strings_column_wrapper const sha1_string_results1({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); strings_column_wrapper const sha1_string_results2({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col({0, 100, -100, limits::min(), limits::max()}); @@ -747,8 +746,8 @@ TEST_F(SHA1HashTest, MultiValue) fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0}); fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0}); - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); auto const sha1_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA1); auto const sha1_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA1); EXPECT_EQ(string_input1.num_rows(), sha1_string_output1->size()); @@ -756,8 +755,8 @@ TEST_F(SHA1HashTest, MultiValue) CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output1->view(), sha1_string_results1); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output2->view(), sha1_string_results2); - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); auto const sha1_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); auto const sha1_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); EXPECT_EQ(input1.num_rows(), sha1_output1->size()); @@ -770,9 +769,9 @@ TEST_F(SHA1HashTest, MultiValue) // strings_column_wrapper const strings_col1( // {"", // "Different but null!", -// "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in the " -// "MD5 hash function. This string needed to be longer.", -// "All work and no play makes Jack a dull boy", +// "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in +// the " "MD5 hash function. This string needed to be longer.", "All work and no play makes +// Jack a dull boy", // "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, // {1, 0, 0, 1, 0}); // strings_column_wrapper const strings_col2( From ade59b7f5fbaaeaa594f99604abeb88e004ca665 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 12:23:16 -0700 Subject: [PATCH 004/100] Update comments and docstrings, enable SHA-1. --- .../cudf/detail/utilities/hash_functions.cuh | 2 +- cpp/src/hash/md5_hash.cu | 1 + cpp/src/hash/sha_hash.cu | 25 ++++++++----------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index cdf13fc8f03..cc4a24668b8 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -368,7 +368,7 @@ struct SHA1Hash { } /** - * @brief Core SHA1 algorithm implementation. Processes a single 512-bit chunk, + * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. */ void __device__ hash_step(sha1_intermediate_data* hash_state) const diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 973f3204c37..2b1ad9168da 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -44,6 +44,7 @@ std::unique_ptr md5_hash(table_view const& input, rmm::mr::device_memory_resource* mr) { if (input.num_columns() == 0 || input.num_rows() == 0) { + // Return the MD5 hash of a zero-length input. const string_scalar string_128bit("d41d8cd98f00b204e9orig98ecf8427e"); auto output = make_column_from_scalar(string_128bit, input.num_rows(), stream, mr); return output; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c5c00f7f647..ba851e6e2e5 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -44,6 +44,7 @@ std::unique_ptr sha1_hash(table_view const& input, rmm::mr::device_memory_resource* mr) { if (input.num_columns() == 0 || input.num_rows() == 0) { + // Return the SHA-1 hash of a zero-length input. const string_scalar string_160bit("da39a3ee5e6b4b0d3255bfef95601890afd80709"); auto output = make_column_from_scalar(string_160bit, input.num_rows(), stream, mr); return output; @@ -51,14 +52,12 @@ std::unique_ptr sha1_hash(table_view const& input, CUDF_EXPECTS( std::all_of(input.begin(), input.end(), [](auto col) { return sha_type_check(col.type()); }), - "SHA1 unsupported column type"); + "SHA-1 unsupported column type"); // Result column allocation and creation auto begin = thrust::make_constant_iterator(40); auto offsets_column = cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), stream, mr); - auto offsets_view = offsets_column->view(); - auto d_new_offsets = offsets_view.data(); auto chars_column = strings::detail::create_chars_child_column(input.num_rows() * 40, stream, mr); auto chars_view = chars_column->mutable_view(); @@ -66,7 +65,6 @@ std::unique_ptr sha1_hash(table_view const& input, rmm::device_buffer null_mask{0, stream, mr}; - bool const nullable = has_nulls(input); auto const device_input = table_device_view::create(input, stream); // Hash each row, hashing each element sequentially left to right @@ -76,16 +74,15 @@ std::unique_ptr sha1_hash(table_view const& input, [d_chars, device_input = *device_input] __device__(auto row_index) { sha1_intermediate_data hash_state; SHA1Hash hasher = SHA1Hash{}; - // for (int col_index = 0; col_index < device_input.num_columns(); col_index++) - // { - // if (device_input.column(col_index).is_valid(row_index)) { - // cudf::type_dispatcher(device_input.column(col_index).type(), - // hasher, - // device_input.column(col_index), - // row_index, - // &hash_state); - // } - // } + for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { + if (device_input.column(col_index).is_valid(row_index)) { + cudf::type_dispatcher(device_input.column(col_index).type(), + hasher, + device_input.column(col_index), + row_index, + &hash_state); + } + } hasher.finalize(&hash_state, d_chars + (row_index * 40)); }); From ec4673e5cc23a9530bc5d1d90a171bef15f38917 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 12:24:34 -0700 Subject: [PATCH 005/100] Add test values for SHA-1. --- cpp/tests/hashing/hash_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index aa9a8db4f50..9ac4ce846c9 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -728,10 +728,10 @@ TEST_F(SHA1HashTest, MultiValue) "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); strings_column_wrapper const sha1_string_results1({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + "76bc1090acf2b7384496da688dc542c0a971af8a", + "5e1c9f6772fc0f874800fcbfdee7698bd1155a39", + "a62ca720fbab830c8890044eacbeac216f1ca2e4", + "11e16c52273b5669a41d17ec7c187475193f88b3"}); strings_column_wrapper const sha1_string_results2({"da39a3ee5e6b4b0d3255bfef95601890afd80709", "da39a3ee5e6b4b0d3255bfef95601890afd80709", From 25962970ebcca445c3bea1ba8343a3e49b8b359b Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 13:21:43 -0700 Subject: [PATCH 006/100] Remove unused seed value from MD5Hash. --- cpp/include/cudf/detail/utilities/hash_functions.cuh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index cc4a24668b8..669e34d6e3a 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -233,7 +233,7 @@ MD5ListHasher::operator()(column_device_view data_col, struct MD5Hash { MD5Hash() = default; - constexpr MD5Hash(uint32_t seed) : m_seed(seed) {} + constexpr MD5Hash(uint32_t seed) {} void __device__ finalize(md5_intermediate_data* hash_state, char* result_location) const { @@ -305,9 +305,6 @@ struct MD5Hash { { md5_process(col.element(row_index), hash_state); } - - private: - uint32_t m_seed{cudf::DEFAULT_HASH_SEED}; }; template <> From f775bbcfb7b3edfe2db5b09c544586405c9c9c09 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 13:34:35 -0700 Subject: [PATCH 007/100] Use std::memcpy, add comments. --- .../cudf/detail/utilities/hash_functions.cuh | 30 ++++++++----------- cpp/src/hash/hash_constants.hpp | 1 - cpp/src/hash/sha_hash.cu | 13 ++++---- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 669e34d6e3a..54cdc09fd87 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -371,12 +371,7 @@ struct SHA1Hash { void __device__ hash_step(sha1_intermediate_data* hash_state) const { uint32_t temp_hash[5]; - thrust::copy_n(thrust::seq, hash_state->hash_value, 5, temp_hash); - // temp_hash[0] = hash_state->hash_value[0]; - // temp_hash[1] = hash_state->hash_value[1]; - // temp_hash[2] = hash_state->hash_value[2]; - // temp_hash[3] = hash_state->hash_value[3]; - // temp_hash[4] = hash_state->hash_value[4]; + std::memcpy(temp_hash, hash_state->hash_value, 5); uint32_t words[80]; for (int i = 0; i < 16; i++) { @@ -450,21 +445,21 @@ struct SHA1Hash { // 64 bytes for the number of bytes processed in a given step constexpr int sha1_chunk_size = 64; if (hash_state->buffer_length + len < sha1_chunk_size) { - thrust::copy_n(thrust::seq, data, len, hash_state->buffer + hash_state->buffer_length); + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; - thrust::copy_n(thrust::seq, data, copylen, hash_state->buffer + hash_state->buffer_length); + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); hash_step(hash_state); while (len > sha1_chunk_size + copylen) { - thrust::copy_n(thrust::seq, data + copylen, sha1_chunk_size, hash_state->buffer); + std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); hash_step(hash_state); copylen += sha1_chunk_size; } - thrust::copy_n(thrust::seq, data + copylen, len - copylen, hash_state->buffer); + std::memcpy(hash_state->buffer, data + copylen, len - copylen); hash_state->buffer_length = len - copylen; } } @@ -496,10 +491,9 @@ struct SHA1Hash { thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); } - thrust::copy_n(thrust::seq, - reinterpret_cast(&full_length), - message_length_size, - hash_state->buffer + sha1_chunk_size - message_length_size); + std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, + reinterpret_cast(&full_length), + message_length_size); hash_step(hash_state); // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); @@ -573,20 +567,20 @@ void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( hash_state->message_length += len; if (hash_state->buffer_length + len < 64) { - thrust::copy_n(thrust::seq, data, len, hash_state->buffer + hash_state->buffer_length); + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { uint32_t copylen = 64 - hash_state->buffer_length; - thrust::copy_n(thrust::seq, data, copylen, hash_state->buffer + hash_state->buffer_length); + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); hash_step(hash_state); while (len > 64 + copylen) { - thrust::copy_n(thrust::seq, data + copylen, 64, hash_state->buffer); + std::memcpy(hash_state->buffer, data + copylen, 64); hash_step(hash_state); copylen += 64; } - thrust::copy_n(thrust::seq, data + copylen, len - copylen, hash_state->buffer); + std::memcpy(hash_state->buffer, data + copylen, len - copylen); hash_state->buffer_length = len - copylen; } } diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index dd869b44912..458d4fc54b6 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -67,7 +67,6 @@ struct sha1_intermediate_data { uint64_t message_length = 0; uint32_t buffer_length = 0; uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; - // uint32_t hash_value[5] = {0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210, 0xf0e1d2c3}; uint8_t buffer[64]; }; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index ba851e6e2e5..5562b489ff5 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -50,6 +50,8 @@ std::unique_ptr sha1_hash(table_view const& input, return output; } + // Accepts string and fixed width columns. + // TODO: Accept single layer list columns holding those types. CUDF_EXPECTS( std::all_of(input.begin(), input.end(), [](auto col) { return sha_type_check(col.type()); }), "SHA-1 unsupported column type"); @@ -76,11 +78,12 @@ std::unique_ptr sha1_hash(table_view const& input, SHA1Hash hasher = SHA1Hash{}; for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { - cudf::type_dispatcher(device_input.column(col_index).type(), - hasher, - device_input.column(col_index), - row_index, - &hash_state); + cudf::type_dispatcher( + device_input.column(col_index).type(), + hasher, + device_input.column(col_index), + row_index, + &hash_state); } } hasher.finalize(&hash_state, d_chars + (row_index * 40)); From 955dadf3d74bda3bffaac941da8289f78d936333 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 17:54:26 -0700 Subject: [PATCH 008/100] Use __byte_perm to swap endianness. --- cpp/include/cudf/detail/utilities/hash_functions.cuh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 54cdc09fd87..d48f3bc1afa 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -377,12 +377,8 @@ struct SHA1Hash { for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); - // words[i] = buffer_element_as_int; - - words[i] = (buffer_element_as_int << 24) & 0xff000000; - words[i] |= (buffer_element_as_int << 8) & 0xff0000; - words[i] |= (buffer_element_as_int >> 8) & 0xff00; - words[i] |= (buffer_element_as_int >> 24) & 0xff; + // Convert word representation from little-endian to big-endian + words[i] = __byte_perm(buffer_element_as_int, 0, 0x0123); } // std::memcpy(words, hash_state->buffer, 64); for (int i = 16; i < 80; i++) { From 7dd9a9ea89ed404a46444b58e3c63019d8c2b708 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 18:31:21 -0700 Subject: [PATCH 009/100] Update comments. --- cpp/include/cudf/detail/utilities/hash_functions.cuh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index d48f3bc1afa..530adebf470 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -374,13 +374,16 @@ struct SHA1Hash { std::memcpy(temp_hash, hash_state->hash_value, 5); uint32_t words[80]; + + // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); - // Convert word representation from little-endian to big-endian + // Convert word representation from little-endian to big-endian. words[i] = __byte_perm(buffer_element_as_int, 0, 0x0123); } - // std::memcpy(words, hash_state->buffer, 64); + + // The rest of the 80 words are generated from the first 16 words. for (int i = 16; i < 80; i++) { uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; words[i] = rotl32(temp, 1); From 77136bc60137d44e0702e8a9dd605bc7b6fb72f6 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 7 Sep 2021 18:32:07 -0700 Subject: [PATCH 010/100] Update for changes to cudf::make_strings_column API. --- cpp/src/hash/sha_hash.cu | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 5562b489ff5..6d11e3710a2 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -89,13 +89,8 @@ std::unique_ptr sha1_hash(table_view const& input, hasher.finalize(&hash_state, d_chars + (row_index * 40)); }); - return make_strings_column(input.num_rows(), - std::move(offsets_column), - std::move(chars_column), - 0, - std::move(null_mask), - stream, - mr); + return make_strings_column( + input.num_rows(), std::move(offsets_column), std::move(chars_column), 0, std::move(null_mask)); } std::unique_ptr sha256_hash(table_view const& input, From 4f7e0d484472f92c0e576bf3a79372ca2a0d2b11 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 06:17:30 -0700 Subject: [PATCH 011/100] Make rotl32 a CUDA_DEVICE_CALLABLE, use __funnelshift_l intrinsic. --- cpp/include/cudf/detail/utilities/hash_functions.cuh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 530adebf470..fd32627d812 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -359,9 +359,10 @@ void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, } struct SHA1Hash { - CUDA_HOST_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const + CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const { - return (x << r) | (x >> (32 - r)); + // return (x << r) | (x >> (32 - r)); + return __funnelshift_l(x, x, r); } /** @@ -387,7 +388,6 @@ struct SHA1Hash { for (int i = 16; i < 80; i++) { uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; words[i] = rotl32(temp, 1); - // words[i] = __funnelshift_l(temp, temp, 1); } // #pragma unroll From e42b5a2517beb9842e0a5f86373bd7d62c563f91 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 10:47:23 -0700 Subject: [PATCH 012/100] Add comments. --- cpp/include/cudf/types.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/include/cudf/types.hpp b/cpp/include/cudf/types.hpp index 1df2eb400bb..4f82bfac491 100644 --- a/cpp/include/cudf/types.hpp +++ b/cpp/include/cudf/types.hpp @@ -336,11 +336,11 @@ enum class hash_id { HASH_MD5, ///< MD5 hash function HASH_SERIAL_MURMUR3, ///< Serial Murmur3 hash function HASH_SPARK_MURMUR3, ///< Spark Murmur3 hash function - HASH_SHA1, - HASH_SHA224, - HASH_SHA256, - HASH_SHA384, - HASH_SHA512 + HASH_SHA1, ///< SHA-1 hash function + HASH_SHA224, ///< SHA-224 hash function + HASH_SHA256, ///< SHA-256 hash function + HASH_SHA384, ///< SHA-384 hash function + HASH_SHA512 ///< SHA-512 hash function }; /** From 070ee5ff1642c01447d40fe181b61421ea52a165 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 10:48:23 -0700 Subject: [PATCH 013/100] Move MD5 and SHA functions to the only .cu file that uses them. --- .../cudf/detail/utilities/hash_functions.cuh | 533 ------------------ cpp/src/hash/md5_hash.cu | 308 +++++++++- cpp/src/hash/sha_hash.cu | 230 +++++++- 3 files changed, 536 insertions(+), 535 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index fd32627d812..24778c9e37e 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -27,104 +27,6 @@ using hash_value_type = uint32_t; namespace cudf { namespace detail { -namespace { -/** - * @brief Core MD5 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ -void CUDA_DEVICE_CALLABLE md5_hash_step(md5_intermediate_data* hash_state) -{ - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - - for (unsigned int j = 0; j < 64; j++) { - uint32_t F; - uint32_t g; - switch (j / 16) { - case 0: - F = (B & C) | ((~B) & D); - g = j; - break; - case 1: - F = (D & B) | ((~D) & C); - g = (5 * j + 1) % 16; - break; - case 2: - F = B ^ C ^ D; - g = (3 * j + 5) % 16; - break; - case 3: - F = C ^ (B | (~D)); - g = (7 * j) % 16; - break; - } - - uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + g * 4, 4); - F = F + A + md5_hash_constants[j] + buffer_element_as_int; - A = D; - D = C; - C = B; - B = B + __funnelshift_l(F, F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); - } - - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - - hash_state->buffer_length = 0; -} - -/** - * @brief Core MD5 element processing function - */ -template -void CUDA_DEVICE_CALLABLE md5_process(TKey const& key, md5_intermediate_data* hash_state) -{ - uint32_t const len = sizeof(TKey); - uint8_t const* data = reinterpret_cast(&key); - hash_state->message_length += len; - - // 64 bytes for the number of byt es processed in a given step - constexpr int md5_chunk_size = 64; - if (hash_state->buffer_length + len < md5_chunk_size) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = md5_chunk_size - hash_state->buffer_length; - - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > md5_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); - md5_hash_step(hash_state); - copylen += md5_chunk_size; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } -} - -/** - * Normalization of floating point NANs and zeros helper - */ -template ::value>* = nullptr> -T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros_helper(T key) -{ - if (isnan(key)) { - return std::numeric_limits::quiet_NaN(); - } else if (key == T{0.0}) { - return T{0.0}; - } else { - return key; - } -} -} // namespace /** * Modified GPU implementation of @@ -149,441 +51,6 @@ void CUDA_DEVICE_CALLABLE uint32ToLowercaseHexString(uint32_t num, char* destina std::memcpy(destination, reinterpret_cast(&x), 8); } -struct MD5ListHasher { - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported chrono type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) { - md5_process(normalize_nans_and_zeros_helper(data_col.element(i)), hash_state); - } - } - } - - template < - typename T, - std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) md5_process(data_col.element(i), hash_state); - } - } -}; - -template <> -void CUDA_DEVICE_CALLABLE -MD5ListHasher::operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const -{ - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) { - string_view key = data_col.element(i); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - - hash_state->message_length += len; - - if (hash_state->buffer_length + len < 64) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = 64 - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); - md5_hash_step(hash_state); - copylen += 64; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } - } - } -} - -struct MD5Hash { - MD5Hash() = default; - constexpr MD5Hash(uint32_t seed) {} - - void __device__ finalize(md5_intermediate_data* hash_state, char* result_location) const - { - auto const full_length = (static_cast(hash_state->message_length)) << 3; - thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - - // 64 bytes for the number of bytes processed in a given step - constexpr int md5_chunk_size = 64; - // 8 bytes for the total message length, appended to the end of the last chunk processed - constexpr int message_length_size = 8; - // 1 byte for the end of the message flag - constexpr int end_of_message_size = 1; - if (hash_state->buffer_length + message_length_size + end_of_message_size <= md5_chunk_size) { - thrust::fill_n( - thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (md5_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), - 0x00); - } else { - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (md5_chunk_size - hash_state->buffer_length), - 0x00); - md5_hash_step(hash_state); - - thrust::fill_n(thrust::seq, hash_state->buffer, md5_chunk_size - message_length_size, 0x00); - } - - std::memcpy(hash_state->buffer + md5_chunk_size - message_length_size, - reinterpret_cast(&full_length), - message_length_size); - md5_hash_step(hash_state); - -#pragma unroll - for (int i = 0; i < 4; ++i) - uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported chrono type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - md5_process(normalize_nans_and_zeros_helper(col.element(row_index)), hash_state); - } - - template < - typename T, - std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - md5_process(col.element(row_index), hash_state); - } -}; - -template <> -void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const -{ - string_view key = col.element(row_index); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - - hash_state->message_length += len; - - if (hash_state->buffer_length + len < 64) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = 64 - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); - md5_hash_step(hash_state); - copylen += 64; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } -} - -template <> -void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const -{ - static constexpr size_type offsets_column_index{0}; - static constexpr size_type data_column_index{1}; - - column_device_view offsets = col.child(offsets_column_index); - column_device_view data = col.child(data_column_index); - - if (data.type().id() == type_id::LIST) cudf_assert(false && "Nested list unsupported"); - - cudf::type_dispatcher(data.type(), - MD5ListHasher{}, - data, - offsets.element(row_index), - offsets.element(row_index + 1), - hash_state); -} - -struct SHA1Hash { - CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const - { - // return (x << r) | (x >> (32 - r)); - return __funnelshift_l(x, x, r); - } - - /** - * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - void __device__ hash_step(sha1_intermediate_data* hash_state) const - { - uint32_t temp_hash[5]; - std::memcpy(temp_hash, hash_state->hash_value, 5); - - uint32_t words[80]; - - // The 512-bit message buffer fills the first 16 words. - for (int i = 0; i < 16; i++) { - uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); - // Convert word representation from little-endian to big-endian. - words[i] = __byte_perm(buffer_element_as_int, 0, 0x0123); - } - - // The rest of the 80 words are generated from the first 16 words. - for (int i = 16; i < 80; i++) { - uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = rotl32(temp, 1); - } - - // #pragma unroll - for (int i = 0; i < 80; i++) { - uint32_t F; - uint32_t temp; - uint32_t k; - switch (i / 20) { - case 0: - // F = (temp_hash[1] & temp_hash[2]) | ((~temp_hash[1]) & temp_hash[3]); - F = ((temp_hash[1] & (temp_hash[2] ^ temp_hash[3])) ^ temp_hash[3]); - k = 0x5a827999; - break; - case 1: - F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; - k = 0x6ed9eba1; - break; - case 2: - F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | - (temp_hash[2] & temp_hash[3]); - k = 0x8f1bbcdc; - break; - case 3: - F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; - k = 0xca62c1d6; - break; - } - temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; - // temp = __funnelshift_l(temp_hash[0], temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; - temp_hash[4] = temp_hash[3]; - temp_hash[3] = temp_hash[2]; - // temp_hash[2] = __funnelshift_l(temp_hash[1], temp_hash[1], 30); - temp_hash[2] = rotl32(temp_hash[1], 30); - temp_hash[1] = temp_hash[0]; - temp_hash[0] = temp; - } - -#pragma unroll - for (int i = 0; i < 5; i++) { - hash_state->hash_value[i] = hash_state->hash_value[i] + temp_hash[i]; - } - } - - /** - * @brief Core SHA1 element processing function - */ - template - void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const - { - uint32_t const len = sizeof(TKey); - uint8_t const* data = reinterpret_cast(&key); - hash_state->message_length += len; - - // 64 bytes for the number of bytes processed in a given step - constexpr int sha1_chunk_size = 64; - if (hash_state->buffer_length + len < sha1_chunk_size) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; - - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - hash_step(hash_state); - - while (len > sha1_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); - hash_step(hash_state); - copylen += sha1_chunk_size; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } - } - - void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const - { - auto const full_length = (static_cast(hash_state->message_length)) << 3; - thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - - // 64 bytes for the number of bytes processed in a given step - constexpr int sha1_chunk_size = 64; - // 8 bytes for the total message length, appended to the end of the last chunk processed - constexpr int message_length_size = 8; - // 1 byte for the end of the message flag - constexpr int end_of_message_size = 1; - if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { - thrust::fill_n( - thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), - 0x00); - } else { - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - hash_state->buffer_length), - 0x00); - hash_step(hash_state); - - thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); - } - - std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, - reinterpret_cast(&full_length), - message_length_size); - hash_step(hash_state); - // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); - -#pragma unroll - for (int i = 0; i < 5; ++i) { - uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; - flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; - flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; - flipped |= (hash_state->hash_value[i] >> 24) & 0xff; - uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - - // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); - - // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); - // std::memcpy(hash_state->hash_value, &full_length, 8); - // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); - } - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported chrono type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const - { - T const& key = col.element(row_index); - if (isnan(key)) { - T nan = std::numeric_limits::quiet_NaN(); - process(nan, hash_state); - } else if (key == T{0.0}) { - process(T{0.0}, hash_state); - } else { - process(key, hash_state); - } - } - - template () && !is_floating_point() && - !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const - { - process(col.element(row_index), hash_state); - } -}; - -template <> -void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( - column_device_view col, size_type row_index, sha1_intermediate_data* hash_state) const -{ - string_view key = col.element(row_index); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - - hash_state->message_length += len; - - if (hash_state->buffer_length + len < 64) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = 64 - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - hash_step(hash_state); - - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); - hash_step(hash_state); - copylen += 64; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } -} - } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 2b1ad9168da..e2101e190c9 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -27,6 +27,9 @@ #include namespace cudf { + +namespace detail { + namespace { // MD5 supported leaf data type check @@ -35,9 +38,312 @@ bool md5_type_check(data_type dt) return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); } +/** + * @brief Core MD5 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ +void CUDA_DEVICE_CALLABLE md5_hash_step(md5_intermediate_data* hash_state) +{ + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + + for (unsigned int j = 0; j < 64; j++) { + uint32_t F; + uint32_t g; + switch (j / 16) { + case 0: + F = (B & C) | ((~B) & D); + g = j; + break; + case 1: + F = (D & B) | ((~D) & C); + g = (5 * j + 1) % 16; + break; + case 2: + F = B ^ C ^ D; + g = (3 * j + 5) % 16; + break; + case 3: + F = C ^ (B | (~D)); + g = (7 * j) % 16; + break; + } + + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + g * 4, 4); + F = F + A + md5_hash_constants[j] + buffer_element_as_int; + A = D; + D = C; + C = B; + B = B + __funnelshift_l(F, F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + + hash_state->buffer_length = 0; +} + +/** + * @brief Core MD5 element processing function + */ +template +void CUDA_DEVICE_CALLABLE md5_process(TKey const& key, md5_intermediate_data* hash_state) +{ + uint32_t const len = sizeof(TKey); + uint8_t const* data = reinterpret_cast(&key); + hash_state->message_length += len; + + // 64 bytes for the number of byt es processed in a given step + constexpr int md5_chunk_size = 64; + if (hash_state->buffer_length + len < md5_chunk_size) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = md5_chunk_size - hash_state->buffer_length; + + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > md5_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); + md5_hash_step(hash_state); + copylen += md5_chunk_size; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } +} + +/** + * Normalization of floating point NANs and zeros helper + */ +template ::value>* = nullptr> +T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros_helper(T key) +{ + if (isnan(key)) { + return std::numeric_limits::quiet_NaN(); + } else if (key == T{0.0}) { + return T{0.0}; + } else { + return key; + } +} } // namespace -namespace detail { +struct MD5ListHasher { + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported chrono type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) { + md5_process(normalize_nans_and_zeros_helper(data_col.element(i)), hash_state); + } + } + } + + template < + typename T, + std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) md5_process(data_col.element(i), hash_state); + } + } +}; + +template <> +void CUDA_DEVICE_CALLABLE +MD5ListHasher::operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const +{ + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) { + string_view key = data_col.element(i); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > 64 + copylen) { + std::memcpy(hash_state->buffer, data + copylen, 64); + md5_hash_step(hash_state); + copylen += 64; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } + } + } +} + +struct MD5Hash { + MD5Hash() = default; + constexpr MD5Hash(uint32_t seed) {} + + void __device__ finalize(md5_intermediate_data* hash_state, char* result_location) const + { + auto const full_length = (static_cast(hash_state->message_length)) << 3; + thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); + + // 64 bytes for the number of bytes processed in a given step + constexpr int md5_chunk_size = 64; + // 8 bytes for the total message length, appended to the end of the last chunk processed + constexpr int message_length_size = 8; + // 1 byte for the end of the message flag + constexpr int end_of_message_size = 1; + if (hash_state->buffer_length + message_length_size + end_of_message_size <= md5_chunk_size) { + thrust::fill_n( + thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (md5_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), + 0x00); + } else { + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (md5_chunk_size - hash_state->buffer_length), + 0x00); + md5_hash_step(hash_state); + + thrust::fill_n(thrust::seq, hash_state->buffer, md5_chunk_size - message_length_size, 0x00); + } + + std::memcpy(hash_state->buffer + md5_chunk_size - message_length_size, + reinterpret_cast(&full_length), + message_length_size); + md5_hash_step(hash_state); + +#pragma unroll + for (int i = 0; i < 4; ++i) + uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported chrono type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + md5_process(normalize_nans_and_zeros_helper(col.element(row_index)), hash_state); + } + + template < + typename T, + std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + md5_process(col.element(row_index), hash_state); + } +}; + +template <> +void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const +{ + string_view key = col.element(row_index); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > 64 + copylen) { + std::memcpy(hash_state->buffer, data + copylen, 64); + md5_hash_step(hash_state); + copylen += 64; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } +} + +template <> +void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const +{ + static constexpr size_type offsets_column_index{0}; + static constexpr size_type data_column_index{1}; + + column_device_view offsets = col.child(offsets_column_index); + column_device_view data = col.child(data_column_index); + + if (data.type().id() == type_id::LIST) cudf_assert(false && "Nested list unsupported"); + + cudf::type_dispatcher(data.type(), + MD5ListHasher{}, + data, + offsets.element(row_index), + offsets.element(row_index + 1), + hash_state); +} std::unique_ptr md5_hash(table_view const& input, rmm::cuda_stream_view stream, diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 6d11e3710a2..7d9b9ad8f05 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -27,6 +27,8 @@ #include namespace cudf { +namespace detail { + namespace { // SHA supported leaf data type check @@ -37,7 +39,233 @@ bool sha_type_check(data_type dt) } // namespace -namespace detail { +struct SHA1Hash { + CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const + { + // return (x << r) | (x >> (32 - r)); + return __funnelshift_l(x, x, r); + } + + /** + * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + void __device__ hash_step(sha1_intermediate_data* hash_state) const + { + uint32_t temp_hash[5]; + std::memcpy(temp_hash, hash_state->hash_value, 5); + + uint32_t words[80]; + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); + // Convert word representation from little-endian to big-endian. + words[i] = __byte_perm(buffer_element_as_int, 0, 0x0123); + } + + // The rest of the 80 words are generated from the first 16 words. + for (int i = 16; i < 80; i++) { + uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotl32(temp, 1); + } + + // printf("Thread %i, word 0 = %08x\n\n", threadIdx.x, words[0]); + + // #pragma unroll + for (int i = 0; i < 80; i++) { + uint32_t F; + uint32_t temp; + uint32_t k; + switch (i / 20) { + case 0: + // F = (temp_hash[1] & temp_hash[2]) | ((~temp_hash[1]) & temp_hash[3]); + F = ((temp_hash[1] & (temp_hash[2] ^ temp_hash[3])) ^ temp_hash[3]); + k = 0x5a827999; + break; + case 1: + F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + k = 0x6ed9eba1; + break; + case 2: + F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | + (temp_hash[2] & temp_hash[3]); + k = 0x8f1bbcdc; + break; + case 3: + F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + k = 0xca62c1d6; + break; + } + temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; + // temp = __funnelshift_l(temp_hash[0], temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; + temp_hash[4] = temp_hash[3]; + temp_hash[3] = temp_hash[2]; + // temp_hash[2] = __funnelshift_l(temp_hash[1], temp_hash[1], 30); + temp_hash[2] = rotl32(temp_hash[1], 30); + temp_hash[1] = temp_hash[0]; + temp_hash[0] = temp; + } + +#pragma unroll + for (int i = 0; i < 5; i++) { + hash_state->hash_value[i] = hash_state->hash_value[i] + temp_hash[i]; + } + } + + /** + * @brief Core SHA1 element processing function + */ + template + void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const + { + uint32_t const len = sizeof(TKey); + uint8_t const* data = reinterpret_cast(&key); + hash_state->message_length += len; + + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + if (hash_state->buffer_length + len < sha1_chunk_size) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; + + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + hash_step(hash_state); + + while (len > sha1_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); + hash_step(hash_state); + copylen += sha1_chunk_size; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } + } + + void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const + { + auto const full_length = (static_cast(hash_state->message_length)) << 3; + thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); + + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + // 8 bytes for the total message length, appended to the end of the last chunk processed + constexpr int message_length_size = 8; + // 1 byte for the end of the message flag + constexpr int end_of_message_size = 1; + if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { + thrust::fill_n( + thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), + 0x00); + } else { + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (sha1_chunk_size - hash_state->buffer_length), + 0x00); + hash_step(hash_state); + + thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); + } + + std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, + reinterpret_cast(&full_length), + message_length_size); + hash_step(hash_state); + // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); + +#pragma unroll + for (int i = 0; i < 5; ++i) { + uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; + flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; + flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; + flipped |= (hash_state->hash_value[i] >> 24) & 0xff; + uint32ToLowercaseHexString(flipped, result_location + (8 * i)); + + // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); + + // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); + // std::memcpy(hash_state->hash_value, &full_length, 8); + // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); + } + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + cudf_assert(false && "SHA-1 Unsupported chrono type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + cudf_assert(false && "SHA-1 Unsupported non-fixed-width type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + T const& key = col.element(row_index); + if (isnan(key)) { + T nan = std::numeric_limits::quiet_NaN(); + process(nan, hash_state); + } else if (key == T{0.0}) { + process(T{0.0}, hash_state); + } else { + process(key, hash_state); + } + } + + template () && !is_floating_point() && + !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha1_intermediate_data* hash_state) const + { + process(col.element(row_index), hash_state); + } +}; + +template <> +void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( + column_device_view col, size_type row_index, sha1_intermediate_data* hash_state) const +{ + string_view key = col.element(row_index); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + hash_step(hash_state); + + while (len > 64 + copylen) { + std::memcpy(hash_state->buffer, data + copylen, 64); + hash_step(hash_state); + copylen += 64; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } +} std::unique_ptr sha1_hash(table_view const& input, cudaStream_t stream, From 252147e41e350fe66cef601d7972b3e6f97ffe12 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 18:43:13 -0700 Subject: [PATCH 014/100] Use named constant for MD5 chunk size. --- cpp/src/hash/md5_hash.cu | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index e2101e190c9..e25accedfb5 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -197,18 +197,20 @@ MD5ListHasher::operator()(column_device_view data_col, hash_state->message_length += len; - if (hash_state->buffer_length + len < 64) { + // 64 bytes for the number of bytes processed in a given step + constexpr int md5_chunk_size = 64; + if (hash_state->buffer_length + len < md5_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { - uint32_t copylen = 64 - hash_state->buffer_length; + uint32_t copylen = md5_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); md5_hash_step(hash_state); - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); + while (len > md5_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); md5_hash_step(hash_state); - copylen += 64; + copylen += md5_chunk_size; } std::memcpy(hash_state->buffer, data + copylen, len - copylen); From d998656375f21b1cb5e1a2bda50149f259809028 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 18:45:01 -0700 Subject: [PATCH 015/100] Fix issue by using named temp variables. --- cpp/src/hash/sha_hash.cu | 45 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 7d9b9ad8f05..36bb0ca5f54 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -52,8 +52,11 @@ struct SHA1Hash { */ void __device__ hash_step(sha1_intermediate_data* hash_state) const { - uint32_t temp_hash[5]; - std::memcpy(temp_hash, hash_state->hash_value, 5); + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + uint32_t E = hash_state->hash_value[4]; uint32_t words[80]; @@ -71,47 +74,43 @@ struct SHA1Hash { words[i] = rotl32(temp, 1); } - // printf("Thread %i, word 0 = %08x\n\n", threadIdx.x, words[0]); - - // #pragma unroll +#pragma unroll for (int i = 0; i < 80; i++) { uint32_t F; uint32_t temp; uint32_t k; switch (i / 20) { case 0: - // F = (temp_hash[1] & temp_hash[2]) | ((~temp_hash[1]) & temp_hash[3]); - F = ((temp_hash[1] & (temp_hash[2] ^ temp_hash[3])) ^ temp_hash[3]); + F = D ^ (B & (C ^ D)); k = 0x5a827999; break; case 1: - F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + F = B ^ C ^ D; k = 0x6ed9eba1; break; case 2: - F = (temp_hash[1] & temp_hash[2]) | (temp_hash[1] & temp_hash[3]) | - (temp_hash[2] & temp_hash[3]); + F = (B & C) | (B & D) | (C & D); k = 0x8f1bbcdc; break; case 3: - F = temp_hash[1] ^ temp_hash[2] ^ temp_hash[3]; + F = B ^ C ^ D; k = 0xca62c1d6; break; } - temp = rotl32(temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; - // temp = __funnelshift_l(temp_hash[0], temp_hash[0], 5) + F + temp_hash[4] + k + words[i]; - temp_hash[4] = temp_hash[3]; - temp_hash[3] = temp_hash[2]; - // temp_hash[2] = __funnelshift_l(temp_hash[1], temp_hash[1], 30); - temp_hash[2] = rotl32(temp_hash[1], 30); - temp_hash[1] = temp_hash[0]; - temp_hash[0] = temp; + temp = rotl32(A, 5) + F + E + k + words[i]; + E = D; + D = C; + C = rotl32(B, 30); + B = A; + A = temp; } -#pragma unroll - for (int i = 0; i < 5; i++) { - hash_state->hash_value[i] = hash_state->hash_value[i] + temp_hash[i]; - } + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + hash_state->buffer_length = 0; } /** From f535d27ceed871d91f8e88c75ec4b31070862eac Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 18:45:23 -0700 Subject: [PATCH 016/100] Use intrinsic for swapping endianness. --- cpp/src/hash/sha_hash.cu | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 36bb0ca5f54..c0b34b94522 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -180,10 +180,8 @@ struct SHA1Hash { #pragma unroll for (int i = 0; i < 5; ++i) { - uint32_t flipped = (hash_state->hash_value[i] << 24) & 0xff000000; - flipped |= (hash_state->hash_value[i] << 8) & 0xff0000; - flipped |= (hash_state->hash_value[i] >> 8) & 0xff00; - flipped |= (hash_state->hash_value[i] >> 24) & 0xff; + // Convert word representation from big-endian to little-endian. + uint32_t flipped = __byte_perm(hash_state->hash_value[i], 0, 0x0123); uint32ToLowercaseHexString(flipped, result_location + (8 * i)); // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); From 9d096f3411429cf568386c4a15cca5fb85082a4f Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 8 Sep 2021 22:55:03 -0700 Subject: [PATCH 017/100] Fix bug in message length. Must be stored as a big-endian 64-bit value. --- cpp/src/hash/sha_hash.cu | 45 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c0b34b94522..b2383bf0421 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -42,7 +42,7 @@ bool sha_type_check(data_type dt) struct SHA1Hash { CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const { - // return (x << r) | (x >> (32 - r)); + // Equivalent to (x << r) | (x >> (32 - r)) return __funnelshift_l(x, x, r); } @@ -147,7 +147,10 @@ struct SHA1Hash { void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const { + // Message length in bits auto const full_length = (static_cast(hash_state->message_length)) << 3; + + // Add a one bit flag to signal the end of the message thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); // 64 bytes for the number of bytes processed in a given step @@ -172,8 +175,20 @@ struct SHA1Hash { thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); } + // Convert the 64-bit message length from little-endian to big-endian. + // There is currently no CUDA intrinsic for permuting bytes in 64 bit integers. + auto uint64_swap_endian = [](uint64_t x) -> uint64_t { + // Reverse the endianness of each 32 bit section + uint32_t low_bits = __byte_perm(x, 0, 0x123); + uint32_t high_bits = __byte_perm(x >> 32, 0, 0x123); + // Reassemble a 64 bit result + uint64_t y = (static_cast(low_bits) << 32) | (static_cast(high_bits)); + return y; + }; + + auto const full_length_flipped = uint64_swap_endian(full_length); std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, - reinterpret_cast(&full_length), + reinterpret_cast(&full_length_flipped), message_length_size); hash_step(hash_state); // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); @@ -183,12 +198,6 @@ struct SHA1Hash { // Convert word representation from big-endian to little-endian. uint32_t flipped = __byte_perm(hash_state->hash_value[i], 0, 0x0123); uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - - // uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); - - // std::memcpy(hash_state->hash_value, hash_state->buffer + 64 + (i * 4), 4); - // std::memcpy(hash_state->hash_value, &full_length, 8); - // uint32ToLowercaseHexString(hash_state->hash_value[0], result_location + (8 * i)); } } @@ -242,23 +251,31 @@ void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( string_view key = col.element(row_index); uint32_t const len = static_cast(key.size_bytes()); uint8_t const* data = reinterpret_cast(key.data()); - hash_state->message_length += len; - if (hash_state->buffer_length + len < 64) { + // 64 bytes for the number of bytes processed in a given step + constexpr int sha1_chunk_size = 64; + if (hash_state->buffer_length + len < sha1_chunk_size) { + // If the buffer will not be filled by this data, we copy the new data into + // the buffer but do not trigger a hash step yet. std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { - uint32_t copylen = 64 - hash_state->buffer_length; + // The buffer will be filled by this data. Copy a chunk of the data to fill + // the buffer and trigger a hash step. + uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); hash_step(hash_state); - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); + // Take buffer-sized chunks of the data and do a hash step on each chunk. + while (len > sha1_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); hash_step(hash_state); - copylen += 64; + copylen += sha1_chunk_size; } + // The remaining data chunk does not fill the buffer. We copy the data into + // the buffer but do not trigger a hash step yet. std::memcpy(hash_state->buffer, data + copylen, len - copylen); hash_state->buffer_length = len - copylen; } From a7a8e6ecc21a24874889a455f588003fc6dbdc79 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Sep 2021 12:32:44 -0700 Subject: [PATCH 018/100] Improve comments. --- cpp/src/hash/md5_hash.cu | 6 +++--- cpp/src/hash/sha_hash.cu | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index e25accedfb5..696fe3652a9 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -98,7 +98,7 @@ void CUDA_DEVICE_CALLABLE md5_process(TKey const& key, md5_intermediate_data* ha uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; - // 64 bytes for the number of byt es processed in a given step + // 64 bytes are processed in each hash step constexpr int md5_chunk_size = 64; if (hash_state->buffer_length + len < md5_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); @@ -197,7 +197,7 @@ MD5ListHasher::operator()(column_device_view data_col, hash_state->message_length += len; - // 64 bytes for the number of bytes processed in a given step + // 64 bytes are processed in each hash step constexpr int md5_chunk_size = 64; if (hash_state->buffer_length + len < md5_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); @@ -229,7 +229,7 @@ struct MD5Hash { auto const full_length = (static_cast(hash_state->message_length)) << 3; thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - // 64 bytes for the number of bytes processed in a given step + // 64 bytes are processed in each hash step constexpr int md5_chunk_size = 64; // 8 bytes for the total message length, appended to the end of the last chunk processed constexpr int message_length_size = 8; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index b2383bf0421..29bf3c6a5ad 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -123,7 +123,7 @@ struct SHA1Hash { uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; - // 64 bytes for the number of bytes processed in a given step + // 64 bytes are processed in each hash step constexpr int sha1_chunk_size = 64; if (hash_state->buffer_length + len < sha1_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); @@ -153,13 +153,14 @@ struct SHA1Hash { // Add a one bit flag to signal the end of the message thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - // 64 bytes for the number of bytes processed in a given step + // 64 bytes are processed in each hash step constexpr int sha1_chunk_size = 64; // 8 bytes for the total message length, appended to the end of the last chunk processed constexpr int message_length_size = 8; // 1 byte for the end of the message flag constexpr int end_of_message_size = 1; if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { + // Fill the remainder of the buffer with zeros thrust::fill_n( thrust::seq, hash_state->buffer + hash_state->buffer_length + 1, @@ -253,7 +254,7 @@ void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( uint8_t const* data = reinterpret_cast(key.data()); hash_state->message_length += len; - // 64 bytes for the number of bytes processed in a given step + // 64 bytes are processed in each hash step constexpr int sha1_chunk_size = 64; if (hash_state->buffer_length + len < sha1_chunk_size) { // If the buffer will not be filled by this data, we copy the new data into From dfb1c9933eb05e9c465292c45540d0c2c1113072 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Sep 2021 12:33:20 -0700 Subject: [PATCH 019/100] Expand anonymous namespace. --- cpp/src/hash/md5_hash.cu | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 696fe3652a9..796aff001d9 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -134,7 +134,6 @@ T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros_helper(T key) return key; } } -} // namespace struct MD5ListHasher { template ()>* = nullptr> @@ -347,6 +346,8 @@ void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, hash_state); } +} // namespace + std::unique_ptr md5_hash(table_view const& input, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) From 9735b2f24c462d1cc010e6b90451f53b55b341e0 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Sep 2021 12:33:53 -0700 Subject: [PATCH 020/100] Clean up SHA implementation and expand tests. --- cpp/src/hash/sha_hash.cu | 1 + cpp/tests/hashing/hash_test.cpp | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 29bf3c6a5ad..470d68d34f2 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -110,6 +110,7 @@ struct SHA1Hash { hash_state->hash_value[2] += C; hash_state->hash_value[3] += D; hash_state->hash_value[4] += E; + hash_state->buffer_length = 0; } diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 9ac4ce846c9..97d70512671 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -721,30 +721,40 @@ TEST_F(SHA1HashTest, MultiValue) { strings_column_wrapper const strings_col( {"", - "A 60 character string to test SHA1's message padding algorithm", + "0", + "A 56 character string to test message padding algorithm.", + "A 63 character string to test message padding algorithm, again.", + "A 64 character string to test message padding algorithm, again!!", "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in the " "SHA1 hash function. This string needed to be longer.", "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); strings_column_wrapper const sha1_string_results1({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "76bc1090acf2b7384496da688dc542c0a971af8a", + "b6589fc6ab0dc82cf12099d1c2d40ab994e8410c", + "cb73203438ab46ea54491c53e288a2703c440c4a", + "c595ebd13a785c1c2659e010a42e2ff9987ef51f", + "4ffaf61804c55b8c2171be548bef2e1d0baca17a", "5e1c9f6772fc0f874800fcbfdee7698bd1155a39", "a62ca720fbab830c8890044eacbeac216f1ca2e4", "11e16c52273b5669a41d17ec7c187475193f88b3"}); strings_column_wrapper const sha1_string_results2({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "da39a3ee5e6b4b0d3255bfef95601890afd80709"}); + "fb96549631c835eb239cd614cc6b5cb7d295121a", + "e3977ee0ea7f238134ec93c79988fa84b7c5d79e", + "f6f75b6fa3c3d8d86b44fcb2c98c9ad4b37dcdd0", + "c7abd431a775c604edf41a62f7f215e7258dc16a", + "9adb7e67efcc8b55ed0cc2597478fab31876c898", + "8c3656f7cb37898f9296c1965000d6da13fed64e", + "b4a848399375ec842c2cb445d98b5f80a4dce94f"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col({0, 100, -100, limits::min(), limits::max()}); + fixed_width_column_wrapper const ints_col( + {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0}); + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); From 4a7d8d2bbde85fd58c22f8e029aeaa221c465fbe Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Sep 2021 12:55:05 -0700 Subject: [PATCH 021/100] Enable all tests. --- cpp/tests/hashing/hash_test.cpp | 216 ++++++++++++++++---------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 97d70512671..cc2fe17bf4a 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -725,8 +725,8 @@ TEST_F(SHA1HashTest, MultiValue) "A 56 character string to test message padding algorithm.", "A 63 character string to test message padding algorithm, again.", "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in the " - "SHA1 hash function. This string needed to be longer.", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); @@ -735,7 +735,7 @@ TEST_F(SHA1HashTest, MultiValue) "cb73203438ab46ea54491c53e288a2703c440c4a", "c595ebd13a785c1c2659e010a42e2ff9987ef51f", "4ffaf61804c55b8c2171be548bef2e1d0baca17a", - "5e1c9f6772fc0f874800fcbfdee7698bd1155a39", + "595965dd18f38087186162c788485fe249242131", "a62ca720fbab830c8890044eacbeac216f1ca2e4", "11e16c52273b5669a41d17ec7c187475193f88b3"}); @@ -744,7 +744,7 @@ TEST_F(SHA1HashTest, MultiValue) "e3977ee0ea7f238134ec93c79988fa84b7c5d79e", "f6f75b6fa3c3d8d86b44fcb2c98c9ad4b37dcdd0", "c7abd431a775c604edf41a62f7f215e7258dc16a", - "9adb7e67efcc8b55ed0cc2597478fab31876c898", + "153fdf20d2bd8ae76241197314d6e0be7fe10f50", "8c3656f7cb37898f9296c1965000d6da13fed64e", "b4a848399375ec842c2cb445d98b5f80a4dce94f"}); @@ -773,109 +773,109 @@ TEST_F(SHA1HashTest, MultiValue) CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_output1->view(), sha1_output2->view()); } -// TEST_F(SHA1HashTest, MultiValueNulls) -// { -// // Nulls with different values should be equal -// strings_column_wrapper const strings_col1( -// {"", -// "Different but null!", -// "A very long (greater than 128 bytes/char string) to test a multi hash-step data point in -// the " "MD5 hash function. This string needed to be longer.", "All work and no play makes -// Jack a dull boy", -// "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, -// {1, 0, 0, 1, 0}); -// strings_column_wrapper const strings_col2( -// {"", -// "A 60 character string to test MD5's message padding algorithm", -// "Very different... but null", -// "All work and no play makes Jack a dull boy", -// ""}, -// {1, 0, 0, 1, 1}); // empty string is equivalent to null - -// // Nulls with different values should be equal -// using limits = std::numeric_limits; -// fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, -// {1, 0, 0, 1, 1}); -// fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, -// {1, 0, 0, 1, 1}); - -// // Nulls with different values should be equal -// // Different truthy values should be equal -// fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); -// fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); - -// auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); -// auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - -// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); -// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - -// EXPECT_EQ(input1.num_rows(), output1->size()); -// expect_columns_equal(output1->view(), output2->view()); -// } - -// template -// class SHA1HashTestTyped : public cudf::test::BaseFixture { -// }; - -// TYPED_TEST_CASE(SHA1HashTestTyped, cudf::test::NumericTypes); - -// TYPED_TEST(SHA1HashTestTyped, Equality) -// { -// fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); -// auto const input = cudf::table_view({col}); - -// // Hash of same input should be equal -// auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA1); -// auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); - -// EXPECT_EQ(input.num_rows(), output1->size()); -// expect_columns_equal(output1->view(), output2->view()); -// } - -// TYPED_TEST(SHA1HashTestTyped, EqualityNulls) -// { -// using T = TypeParam; - -// // Nulls with different values should be equal -// fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); -// fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - -// auto const input1 = cudf::table_view({col1}); -// auto const input2 = cudf::table_view({col2}); - -// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); -// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - -// EXPECT_EQ(input1.num_rows(), output1->size()); -// expect_columns_equal(output1->view(), output2->view()); -// } - -// template -// class SHA1HashTestFloatTyped : public cudf::test::BaseFixture { -// }; - -// TYPED_TEST_CASE(SHA1HashTestFloatTyped, cudf::test::FloatingPointTypes); - -// TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) -// { -// using T = TypeParam; -// T min = std::numeric_limits::min(); -// T max = std::numeric_limits::max(); -// T nan = std::numeric_limits::quiet_NaN(); -// T inf = std::numeric_limits::infinity(); - -// fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); -// fixed_width_column_wrapper const col2( -// {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - -// auto const input1 = cudf::table_view({col1}); -// auto const input2 = cudf::table_view({col2}); - -// auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); -// auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - -// expect_columns_equal(output1->view(), output2->view(), true); -// } +TEST_F(SHA1HashTest, MultiValueNulls) +{ + // Nulls with different values should be equal + strings_column_wrapper const strings_col1( + {"", + "Different but null!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the " + "hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, + {1, 0, 0, 1, 0}); + strings_column_wrapper const strings_col2({"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 1}); // empty string is equivalent to null + + // Nulls with different values should be equal + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + + // Nulls with different values should be equal + // Different truthy values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + + auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); + auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA1HashTestTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA1HashTestTyped, cudf::test::NumericTypes); + +TYPED_TEST(SHA1HashTestTyped, Equality) +{ + fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + auto const input = cudf::table_view({col}); + + // Hash of same input should be equal + auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA1); + auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); + + EXPECT_EQ(input.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +TYPED_TEST(SHA1HashTestTyped, EqualityNulls) +{ + using T = TypeParam; + + // Nulls with different values should be equal + fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA1HashTestFloatTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA1HashTestFloatTyped, cudf::test::FloatingPointTypes); + +TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) +{ + using T = TypeParam; + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + T nan = std::numeric_limits::quiet_NaN(); + T inf = std::numeric_limits::infinity(); + + fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + fixed_width_column_wrapper const col2( + {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + + expect_columns_equal(output1->view(), output2->view()); +} CUDF_TEST_PROGRAM_MAIN() From 585bea463bd6c73755735a2736c206c3349e592e Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Sep 2021 20:53:33 -0700 Subject: [PATCH 022/100] Revert changes to MD5 (separated into #9212). --- .../cudf/detail/utilities/hash_functions.cuh | 309 +++++++++++++++++ cpp/src/hash/md5_hash.cu | 314 +----------------- 2 files changed, 311 insertions(+), 312 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 24778c9e37e..6eab13ae9af 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -27,6 +27,104 @@ using hash_value_type = uint32_t; namespace cudf { namespace detail { +namespace { +/** + * @brief Core MD5 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ +void CUDA_DEVICE_CALLABLE md5_hash_step(md5_intermediate_data* hash_state) +{ + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + + for (unsigned int j = 0; j < 64; j++) { + uint32_t F; + uint32_t g; + switch (j / 16) { + case 0: + F = (B & C) | ((~B) & D); + g = j; + break; + case 1: + F = (D & B) | ((~D) & C); + g = (5 * j + 1) % 16; + break; + case 2: + F = B ^ C ^ D; + g = (3 * j + 5) % 16; + break; + case 3: + F = C ^ (B | (~D)); + g = (7 * j) % 16; + break; + } + + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + g * 4, 4); + F = F + A + md5_hash_constants[j] + buffer_element_as_int; + A = D; + D = C; + C = B; + B = B + __funnelshift_l(F, F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + + hash_state->buffer_length = 0; +} + +/** + * @brief Core MD5 element processing function + */ +template +void CUDA_DEVICE_CALLABLE md5_process(TKey const& key, md5_intermediate_data* hash_state) +{ + uint32_t const len = sizeof(TKey); + uint8_t const* data = reinterpret_cast(&key); + hash_state->message_length += len; + + // 64 bytes for the number of byt es processed in a given step + constexpr int md5_chunk_size = 64; + if (hash_state->buffer_length + len < md5_chunk_size) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = md5_chunk_size - hash_state->buffer_length; + + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > md5_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); + md5_hash_step(hash_state); + copylen += md5_chunk_size; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } +} + +/** + * Normalization of floating point NANs and zeros helper + */ +template ::value>* = nullptr> +T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros_helper(T key) +{ + if (isnan(key)) { + return std::numeric_limits::quiet_NaN(); + } else if (key == T{0.0}) { + return T{0.0}; + } else { + return key; + } +} +} // namespace /** * Modified GPU implementation of @@ -51,6 +149,217 @@ void CUDA_DEVICE_CALLABLE uint32ToLowercaseHexString(uint32_t num, char* destina std::memcpy(destination, reinterpret_cast(&x), 8); } +struct MD5ListHasher { + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported chrono type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) { + md5_process(normalize_nans_and_zeros_helper(data_col.element(i)), hash_state); + } + } + } + + template < + typename T, + std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const + { + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) md5_process(data_col.element(i), hash_state); + } + } +}; + +template <> +void CUDA_DEVICE_CALLABLE +MD5ListHasher::operator()(column_device_view data_col, + size_type offset_begin, + size_type offset_end, + md5_intermediate_data* hash_state) const +{ + for (int i = offset_begin; i < offset_end; i++) { + if (!data_col.is_null(i)) { + string_view key = data_col.element(i); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > 64 + copylen) { + std::memcpy(hash_state->buffer, data + copylen, 64); + md5_hash_step(hash_state); + copylen += 64; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } + } + } +} + +struct MD5Hash { + MD5Hash() = default; + constexpr MD5Hash(uint32_t seed) : m_seed(seed) {} + + void __device__ finalize(md5_intermediate_data* hash_state, char* result_location) const + { + auto const full_length = (static_cast(hash_state->message_length)) << 3; + thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); + + // 64 bytes for the number of bytes processed in a given step + constexpr int md5_chunk_size = 64; + // 8 bytes for the total message length, appended to the end of the last chunk processed + constexpr int message_length_size = 8; + // 1 byte for the end of the message flag + constexpr int end_of_message_size = 1; + if (hash_state->buffer_length + message_length_size + end_of_message_size <= md5_chunk_size) { + thrust::fill_n( + thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (md5_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), + 0x00); + } else { + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + 1, + (md5_chunk_size - hash_state->buffer_length), + 0x00); + md5_hash_step(hash_state); + + thrust::fill_n(thrust::seq, hash_state->buffer, md5_chunk_size - message_length_size, 0x00); + } + + std::memcpy(hash_state->buffer + md5_chunk_size - message_length_size, + reinterpret_cast(&full_length), + message_length_size); + md5_hash_step(hash_state); + +#pragma unroll + for (int i = 0; i < 4; ++i) + uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported chrono type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); + } + + template ()>* = nullptr> + void __device__ operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + md5_process(normalize_nans_and_zeros_helper(col.element(row_index)), hash_state); + } + + template < + typename T, + std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const + { + md5_process(col.element(row_index), hash_state); + } + + private: + uint32_t m_seed{cudf::DEFAULT_HASH_SEED}; +}; + +template <> +void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const +{ + string_view key = col.element(row_index); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + + hash_state->message_length += len; + + if (hash_state->buffer_length + len < 64) { + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + uint32_t copylen = 64 - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + md5_hash_step(hash_state); + + while (len > 64 + copylen) { + std::memcpy(hash_state->buffer, data + copylen, 64); + md5_hash_step(hash_state); + copylen += 64; + } + + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } +} + +template <> +void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, + size_type row_index, + md5_intermediate_data* hash_state) const +{ + static constexpr size_type offsets_column_index{0}; + static constexpr size_type data_column_index{1}; + + column_device_view offsets = col.child(offsets_column_index); + column_device_view data = col.child(data_column_index); + + if (data.type().id() == type_id::LIST) cudf_assert(false && "Nested list unsupported"); + + cudf::type_dispatcher(data.type(), + MD5ListHasher{}, + data, + offsets.element(row_index), + offsets.element(row_index + 1), + hash_state); +} } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 796aff001d9..973f3204c37 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -27,9 +27,6 @@ #include namespace cudf { - -namespace detail { - namespace { // MD5 supported leaf data type check @@ -38,322 +35,15 @@ bool md5_type_check(data_type dt) return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); } -/** - * @brief Core MD5 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ -void CUDA_DEVICE_CALLABLE md5_hash_step(md5_intermediate_data* hash_state) -{ - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - - for (unsigned int j = 0; j < 64; j++) { - uint32_t F; - uint32_t g; - switch (j / 16) { - case 0: - F = (B & C) | ((~B) & D); - g = j; - break; - case 1: - F = (D & B) | ((~D) & C); - g = (5 * j + 1) % 16; - break; - case 2: - F = B ^ C ^ D; - g = (3 * j + 5) % 16; - break; - case 3: - F = C ^ (B | (~D)); - g = (7 * j) % 16; - break; - } - - uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + g * 4, 4); - F = F + A + md5_hash_constants[j] + buffer_element_as_int; - A = D; - D = C; - C = B; - B = B + __funnelshift_l(F, F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); - } - - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - - hash_state->buffer_length = 0; -} - -/** - * @brief Core MD5 element processing function - */ -template -void CUDA_DEVICE_CALLABLE md5_process(TKey const& key, md5_intermediate_data* hash_state) -{ - uint32_t const len = sizeof(TKey); - uint8_t const* data = reinterpret_cast(&key); - hash_state->message_length += len; - - // 64 bytes are processed in each hash step - constexpr int md5_chunk_size = 64; - if (hash_state->buffer_length + len < md5_chunk_size) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = md5_chunk_size - hash_state->buffer_length; - - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > md5_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); - md5_hash_step(hash_state); - copylen += md5_chunk_size; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } -} - -/** - * Normalization of floating point NANs and zeros helper - */ -template ::value>* = nullptr> -T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros_helper(T key) -{ - if (isnan(key)) { - return std::numeric_limits::quiet_NaN(); - } else if (key == T{0.0}) { - return T{0.0}; - } else { - return key; - } -} - -struct MD5ListHasher { - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported chrono type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) { - md5_process(normalize_nans_and_zeros_helper(data_col.element(i)), hash_state); - } - } - } - - template < - typename T, - std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const - { - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) md5_process(data_col.element(i), hash_state); - } - } -}; - -template <> -void CUDA_DEVICE_CALLABLE -MD5ListHasher::operator()(column_device_view data_col, - size_type offset_begin, - size_type offset_end, - md5_intermediate_data* hash_state) const -{ - for (int i = offset_begin; i < offset_end; i++) { - if (!data_col.is_null(i)) { - string_view key = data_col.element(i); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - - hash_state->message_length += len; - - // 64 bytes are processed in each hash step - constexpr int md5_chunk_size = 64; - if (hash_state->buffer_length + len < md5_chunk_size) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = md5_chunk_size - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > md5_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, md5_chunk_size); - md5_hash_step(hash_state); - copylen += md5_chunk_size; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } - } - } -} - -struct MD5Hash { - MD5Hash() = default; - constexpr MD5Hash(uint32_t seed) {} - - void __device__ finalize(md5_intermediate_data* hash_state, char* result_location) const - { - auto const full_length = (static_cast(hash_state->message_length)) << 3; - thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - - // 64 bytes are processed in each hash step - constexpr int md5_chunk_size = 64; - // 8 bytes for the total message length, appended to the end of the last chunk processed - constexpr int message_length_size = 8; - // 1 byte for the end of the message flag - constexpr int end_of_message_size = 1; - if (hash_state->buffer_length + message_length_size + end_of_message_size <= md5_chunk_size) { - thrust::fill_n( - thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (md5_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), - 0x00); - } else { - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (md5_chunk_size - hash_state->buffer_length), - 0x00); - md5_hash_step(hash_state); - - thrust::fill_n(thrust::seq, hash_state->buffer, md5_chunk_size - message_length_size, 0x00); - } - - std::memcpy(hash_state->buffer + md5_chunk_size - message_length_size, - reinterpret_cast(&full_length), - message_length_size); - md5_hash_step(hash_state); - -#pragma unroll - for (int i = 0; i < 4; ++i) - uint32ToLowercaseHexString(hash_state->hash_value[i], result_location + (8 * i)); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported chrono type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - cudf_assert(false && "MD5 Unsupported non-fixed-width type column"); - } - - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - md5_process(normalize_nans_and_zeros_helper(col.element(row_index)), hash_state); - } - - template < - typename T, - std::enable_if_t() && !is_floating_point() && !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const - { - md5_process(col.element(row_index), hash_state); - } -}; - -template <> -void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const -{ - string_view key = col.element(row_index); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - - hash_state->message_length += len; - - if (hash_state->buffer_length + len < 64) { - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - uint32_t copylen = 64 - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - md5_hash_step(hash_state); - - while (len > 64 + copylen) { - std::memcpy(hash_state->buffer, data + copylen, 64); - md5_hash_step(hash_state); - copylen += 64; - } - - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } -} - -template <> -void CUDA_DEVICE_CALLABLE MD5Hash::operator()(column_device_view col, - size_type row_index, - md5_intermediate_data* hash_state) const -{ - static constexpr size_type offsets_column_index{0}; - static constexpr size_type data_column_index{1}; - - column_device_view offsets = col.child(offsets_column_index); - column_device_view data = col.child(data_column_index); - - if (data.type().id() == type_id::LIST) cudf_assert(false && "Nested list unsupported"); - - cudf::type_dispatcher(data.type(), - MD5ListHasher{}, - data, - offsets.element(row_index), - offsets.element(row_index + 1), - hash_state); -} - } // namespace +namespace detail { + std::unique_ptr md5_hash(table_view const& input, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { if (input.num_columns() == 0 || input.num_rows() == 0) { - // Return the MD5 hash of a zero-length input. const string_scalar string_128bit("d41d8cd98f00b204e9orig98ecf8427e"); auto output = make_column_from_scalar(string_128bit, input.num_rows(), stream, mr); return output; From 9ce6f1796cdaf2d0c0cd4ffe20b430dd9d00161c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Fri, 10 Sep 2021 06:37:56 -0700 Subject: [PATCH 023/100] Move endian swaps into functions. --- cpp/src/hash/sha_hash.cu | 46 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 470d68d34f2..6785f277ee0 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -37,15 +37,33 @@ bool sha_type_check(data_type dt) return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); } +CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const +{ + // Equivalent to (x << r) | (x >> (32 - r)) + return __funnelshift_l(x, x, r); +} + +// Swap the endianness of a 32 bit value +CUDA_DEVICE_CALLABLE uint32_t swap_endian_32(uint32_t x) +{ + // The selector 0x0123 reverses the byte order + return __byte_perm(x, 0, 0x0123); +} + +// Swap the endianness of a 64 bit value +// There is no CUDA intrinsic for permuting bytes in 64 bit integers +CUDA_DEVICE_CALLABLE uint64_t swap_endian_64(uint64_t x) +{ + // Reverse the endianness of each 32 bit section + uint32_t low_bits = swap_endian_32(x); + uint32_t high_bits = swap_endian_32(x >> 32); + // Reassemble a 64 bit result, swapping the low bits and high bits + return (static_cast(low_bits) << 32) | (static_cast(high_bits)); +}; + } // namespace struct SHA1Hash { - CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const - { - // Equivalent to (x << r) | (x >> (32 - r)) - return __funnelshift_l(x, x, r); - } - /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -65,7 +83,7 @@ struct SHA1Hash { uint32_t buffer_element_as_int; std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); // Convert word representation from little-endian to big-endian. - words[i] = __byte_perm(buffer_element_as_int, 0, 0x0123); + words[i] = swap_endian_32(buffer_element_as_int); } // The rest of the 80 words are generated from the first 16 words. @@ -178,17 +196,7 @@ struct SHA1Hash { } // Convert the 64-bit message length from little-endian to big-endian. - // There is currently no CUDA intrinsic for permuting bytes in 64 bit integers. - auto uint64_swap_endian = [](uint64_t x) -> uint64_t { - // Reverse the endianness of each 32 bit section - uint32_t low_bits = __byte_perm(x, 0, 0x123); - uint32_t high_bits = __byte_perm(x >> 32, 0, 0x123); - // Reassemble a 64 bit result - uint64_t y = (static_cast(low_bits) << 32) | (static_cast(high_bits)); - return y; - }; - - auto const full_length_flipped = uint64_swap_endian(full_length); + auto const full_length_flipped = swap_endian_64(full_length); std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, reinterpret_cast(&full_length_flipped), message_length_size); @@ -198,7 +206,7 @@ struct SHA1Hash { #pragma unroll for (int i = 0; i < 5; ++i) { // Convert word representation from big-endian to little-endian. - uint32_t flipped = __byte_perm(hash_state->hash_value[i], 0, 0x0123); + uint32_t flipped = swap_endian_32(hash_state->hash_value[i]); uint32ToLowercaseHexString(flipped, result_location + (8 * i)); } } From 516b85724af5fcb85a9d955b88e21a331e239593 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 13 Sep 2021 08:01:03 -0700 Subject: [PATCH 024/100] Draft of unified SHA functions - issues runtime error because it uses device virtual functions that cannot be resolved. --- cpp/src/hash/sha_hash.cu | 343 +++++++++++++++++++++------------------ 1 file changed, 186 insertions(+), 157 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 6785f277ee0..1bd83a26a6f 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -37,14 +38,14 @@ bool sha_type_check(data_type dt) return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); } -CUDA_DEVICE_CALLABLE uint32_t rotl32(uint32_t x, int8_t r) const +CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) { // Equivalent to (x << r) | (x >> (32 - r)) return __funnelshift_l(x, x, r); } // Swap the endianness of a 32 bit value -CUDA_DEVICE_CALLABLE uint32_t swap_endian_32(uint32_t x) +CUDA_DEVICE_CALLABLE uint32_t swap_endian(uint32_t x) { // The selector 0x0123 reverses the byte order return __byte_perm(x, 0, 0x0123); @@ -52,111 +53,54 @@ CUDA_DEVICE_CALLABLE uint32_t swap_endian_32(uint32_t x) // Swap the endianness of a 64 bit value // There is no CUDA intrinsic for permuting bytes in 64 bit integers -CUDA_DEVICE_CALLABLE uint64_t swap_endian_64(uint64_t x) +CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) { // Reverse the endianness of each 32 bit section - uint32_t low_bits = swap_endian_32(x); - uint32_t high_bits = swap_endian_32(x >> 32); + uint32_t low_bits = swap_endian(static_cast(x)); + uint32_t high_bits = swap_endian(static_cast(x >> 32)); // Reassemble a 64 bit result, swapping the low bits and high bits return (static_cast(low_bits) << 32) | (static_cast(high_bits)); }; } // namespace -struct SHA1Hash { - /** - * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - void __device__ hash_step(sha1_intermediate_data* hash_state) const - { - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - uint32_t E = hash_state->hash_value[4]; - - uint32_t words[80]; - - // The 512-bit message buffer fills the first 16 words. - for (int i = 0; i < 16; i++) { - uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * 4), 4); - // Convert word representation from little-endian to big-endian. - words[i] = swap_endian_32(buffer_element_as_int); - } - - // The rest of the 80 words are generated from the first 16 words. - for (int i = 16; i < 80; i++) { - uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = rotl32(temp, 1); - } - -#pragma unroll - for (int i = 0; i < 80; i++) { - uint32_t F; - uint32_t temp; - uint32_t k; - switch (i / 20) { - case 0: - F = D ^ (B & (C ^ D)); - k = 0x5a827999; - break; - case 1: - F = B ^ C ^ D; - k = 0x6ed9eba1; - break; - case 2: - F = (B & C) | (B & D) | (C & D); - k = 0x8f1bbcdc; - break; - case 3: - F = B ^ C ^ D; - k = 0xca62c1d6; - break; - } - temp = rotl32(A, 5) + F + E + k + words[i]; - E = D; - D = C; - C = rotl32(B, 30); - B = A; - A = temp; - } - - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; +template +struct SHAHash { + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = MessageChunkSize; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; + using sha_intermediate_data = IntermediateType; + using sha_word_type = WordType; - hash_state->buffer_length = 0; - } + virtual void __device__ hash_step(sha_intermediate_data* hash_state) const = 0; /** - * @brief Core SHA1 element processing function + * @brief Execute SHA on input data chunks. + * + * This accepts arbitrary data, handles it as bytes, and calls the hash step + * when the buffer is filled up to message_chunk_size bytes. */ template - void __device__ process(TKey const& key, sha1_intermediate_data* hash_state) const + void CUDA_DEVICE_CALLABLE process(TKey const& key, sha_intermediate_data* hash_state) const { uint32_t const len = sizeof(TKey); uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; - // 64 bytes are processed in each hash step - constexpr int sha1_chunk_size = 64; - if (hash_state->buffer_length + len < sha1_chunk_size) { + if (hash_state->buffer_length + len < message_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { - uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; + uint32_t copylen = message_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); hash_step(hash_state); - while (len > sha1_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); + while (len > message_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); hash_step(hash_state); - copylen += sha1_chunk_size; + copylen += message_chunk_size; } std::memcpy(hash_state->buffer, data + copylen, len - copylen); @@ -164,73 +108,87 @@ struct SHA1Hash { } } - void __device__ finalize(sha1_intermediate_data* hash_state, char* result_location) const + /** + * @brief Finalize SHA element processing. + * + * This method fills the remainder of the message buffer with zeros, appends + * the message length (in another step of the hash, if needed), and performs + * the final hash step. + */ + void CUDA_DEVICE_CALLABLE finalize(sha_intermediate_data* hash_state, char* result_location) { - // Message length in bits - auto const full_length = (static_cast(hash_state->message_length)) << 3; + // Message length in bits. + uint64_t const message_length_in_bits = (static_cast(hash_state->message_length)) + << 3; // Add a one bit flag to signal the end of the message - thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, 1, 0x80); - - // 64 bytes are processed in each hash step - constexpr int sha1_chunk_size = 64; - // 8 bytes for the total message length, appended to the end of the last chunk processed - constexpr int message_length_size = 8; + constexpr uint8_t end_of_message = 0x80; // 1 byte for the end of the message flag constexpr int end_of_message_size = 1; - if (hash_state->buffer_length + message_length_size + end_of_message_size <= sha1_chunk_size) { - // Fill the remainder of the buffer with zeros - thrust::fill_n( - thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - message_length_size - end_of_message_size - hash_state->buffer_length), - 0x00); - } else { + + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length, + end_of_message_size, + end_of_message); + + // SHA-512 uses a 128-bit message length instead of a 64-bit message length + // but this code does not support messages with lengths exceeding UINT64_MAX + // bits. We always pad the upper 64 bits with zeros. + constexpr auto message_length_supported_size = sizeof(message_length_in_bits); + + if (hash_state->buffer_length + message_length_size + end_of_message_size <= + message_chunk_size) { + // Fill the remainder of the buffer with zeros up to the space reserved + // for the message length. The message length fits in this hash step. thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length + 1, - (sha1_chunk_size - hash_state->buffer_length), + (message_chunk_size - message_length_supported_size - end_of_message_size - + hash_state->buffer_length), + 0x00); + } else { + // Fill the remainder of the buffer with zeros. The message length doesn't + // fit and will be processed in a subsequent hash step comprised of only + // zeros followed by the message length. + thrust::fill_n(thrust::seq, + hash_state->buffer + hash_state->buffer_length + end_of_message_size, + (message_chunk_size - hash_state->buffer_length), 0x00); hash_step(hash_state); - thrust::fill_n(thrust::seq, hash_state->buffer, sha1_chunk_size - message_length_size, 0x00); + thrust::fill_n( + thrust::seq, hash_state->buffer, message_chunk_size - message_length_size, 0x00); } // Convert the 64-bit message length from little-endian to big-endian. - auto const full_length_flipped = swap_endian_64(full_length); - std::memcpy(hash_state->buffer + sha1_chunk_size - message_length_size, + uint64_t const full_length_flipped = swap_endian(message_length_in_bits); + std::memcpy(hash_state->buffer + message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), - message_length_size); + message_length_supported_size); hash_step(hash_state); - // std::memcpy(hash_state->hash_value, hash_state->buffer, 160); - -#pragma unroll - for (int i = 0; i < 5; ++i) { - // Convert word representation from big-endian to little-endian. - uint32_t flipped = swap_endian_32(hash_state->hash_value[i]); - uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - } - } + }; template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha_intermediate_data* hash_state) const { - cudf_assert(false && "SHA-1 Unsupported chrono type column"); + cudf_assert(false && "SHA Unsupported chrono type column"); } - template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const + template < + typename T, + typename std::enable_if_t() && !std::is_same_v>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha_intermediate_data* hash_state) const { - cudf_assert(false && "SHA-1 Unsupported non-fixed-width type column"); + cudf_assert(false && "SHA Unsupported non-fixed-width type column"); } template ()>* = nullptr> - void __device__ operator()(column_device_view col, - size_type row_index, - sha1_intermediate_data* hash_state) const + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha_intermediate_data* hash_state) const { T const& key = col.element(row_index); if (isnan(key)) { @@ -248,48 +206,119 @@ struct SHA1Hash { !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha1_intermediate_data* hash_state) const + sha_intermediate_data* hash_state) const { process(col.element(row_index), hash_state); } -}; -template <> -void CUDA_DEVICE_CALLABLE SHA1Hash::operator()( - column_device_view col, size_type row_index, sha1_intermediate_data* hash_state) const -{ - string_view key = col.element(row_index); - uint32_t const len = static_cast(key.size_bytes()); - uint8_t const* data = reinterpret_cast(key.data()); - hash_state->message_length += len; - - // 64 bytes are processed in each hash step - constexpr int sha1_chunk_size = 64; - if (hash_state->buffer_length + len < sha1_chunk_size) { - // If the buffer will not be filled by this data, we copy the new data into - // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - // The buffer will be filled by this data. Copy a chunk of the data to fill - // the buffer and trigger a hash step. - uint32_t copylen = sha1_chunk_size - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - hash_step(hash_state); + template >* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view col, + size_type row_index, + sha_intermediate_data* hash_state) const + { + string_view key = col.element(row_index); + uint32_t const len = static_cast(key.size_bytes()); + uint8_t const* data = reinterpret_cast(key.data()); + hash_state->message_length += len; - // Take buffer-sized chunks of the data and do a hash step on each chunk. - while (len > sha1_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, sha1_chunk_size); + if (hash_state->buffer_length + len < message_chunk_size) { + // If the buffer will not be filled by this data, we copy the new data into + // the buffer but do not trigger a hash step yet. + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); + hash_state->buffer_length += len; + } else { + // The buffer will be filled by this data. Copy a chunk of the data to fill + // the buffer and trigger a hash step. + uint32_t copylen = message_chunk_size - hash_state->buffer_length; + std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); hash_step(hash_state); - copylen += sha1_chunk_size; + + // Take buffer-sized chunks of the data and do a hash step on each chunk. + while (len > message_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); + hash_step(hash_state); + copylen += message_chunk_size; + } + + // The remaining data chunk does not fill the buffer. We copy the data into + // the buffer but do not trigger a hash step yet. + std::memcpy(hash_state->buffer, data + copylen, len - copylen); + hash_state->buffer_length = len - copylen; + } + } +}; + +struct SHA1Hash : SHAHash { + /** + * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + virtual void __device__ hash_step(sha_intermediate_data* hash_state) const + { + sha_word_type A = hash_state->hash_value[0]; + sha_word_type B = hash_state->hash_value[1]; + sha_word_type C = hash_state->hash_value[2]; + sha_word_type D = hash_state->hash_value[3]; + sha_word_type E = hash_state->hash_value[4]; + + sha_word_type words[80]; + + // Word size in bytes + constexpr auto word_size = sizeof(sha_word_type); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + sha_word_type buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } + + // The rest of the 80 words are generated from the first 16 words. + for (int i = 16; i < 80; i++) { + sha_word_type temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotate_bits_left(temp, 1); } - // The remaining data chunk does not fill the buffer. We copy the data into - // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; + for (int i = 0; i < 80; i++) { + sha_word_type F; + sha_word_type temp; + sha_word_type k; + switch (i / 20) { + case 0: + F = D ^ (B & (C ^ D)); + k = 0x5a827999; + break; + case 1: + F = B ^ C ^ D; + k = 0x6ed9eba1; + break; + case 2: + F = (B & C) | (B & D) | (C & D); + k = 0x8f1bbcdc; + break; + case 3: + F = B ^ C ^ D; + k = 0xca62c1d6; + break; + } + temp = rotate_bits_left(A, 5) + F + E + k + words[i]; + E = D; + D = C; + C = rotate_bits_left(B, 30); + B = A; + A = temp; + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + + hash_state->buffer_length = 0; } -} +}; std::unique_ptr sha1_hash(table_view const& input, cudaStream_t stream, From f4e8c70d048218141c19430b0c6af4cc7f387cc9 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 12:06:56 -0700 Subject: [PATCH 025/100] Use CRTP design. Also add back missing code to write the output. --- cpp/src/hash/sha_hash.cu | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 1bd83a26a6f..2711d626a06 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -64,7 +64,7 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) } // namespace -template +template struct SHAHash { // Number of bytes processed in each hash step static constexpr auto message_chunk_size = MessageChunkSize; @@ -73,8 +73,6 @@ struct SHAHash { using sha_intermediate_data = IntermediateType; using sha_word_type = WordType; - virtual void __device__ hash_step(sha_intermediate_data* hash_state) const = 0; - /** * @brief Execute SHA on input data chunks. * @@ -95,11 +93,11 @@ struct SHAHash { uint32_t copylen = message_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - hash_step(hash_state); + Hasher::hash_step(hash_state); while (len > message_chunk_size + copylen) { std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); - hash_step(hash_state); + Hasher::hash_step(hash_state); copylen += message_chunk_size; } @@ -153,7 +151,7 @@ struct SHAHash { hash_state->buffer + hash_state->buffer_length + end_of_message_size, (message_chunk_size - hash_state->buffer_length), 0x00); - hash_step(hash_state); + Hasher::hash_step(hash_state); thrust::fill_n( thrust::seq, hash_state->buffer, message_chunk_size - message_length_size, 0x00); @@ -164,7 +162,23 @@ struct SHAHash { std::memcpy(hash_state->buffer + message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), message_length_supported_size); - hash_step(hash_state); + Hasher::hash_step(hash_state); + +#pragma unroll + for (int i = 0; i < 5; i++) { + // Convert word representation from big-endian to little-endian. + sha_word_type flipped = swap_endian(hash_state->hash_value[i]); + if constexpr (std::is_same_v) { + uint32ToLowercaseHexString(flipped, result_location + (8 * i)); + } else if constexpr (std::is_same_v) { + uint32_t low_bits = static_cast(flipped); + uint32ToLowercaseHexString(low_bits, result_location + (16 * i)); + uint32_t high_bits = static_cast(flipped >> 32); + uint32ToLowercaseHexString(high_bits, result_location + (16 * i) + 8); + } else { + cudf_assert(false && "Unsupported SHA word type."); + } + } }; template ()>* = nullptr> @@ -231,12 +245,12 @@ struct SHAHash { // the buffer and trigger a hash step. uint32_t copylen = message_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - hash_step(hash_state); + Hasher::hash_step(hash_state); // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > message_chunk_size + copylen) { std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); - hash_step(hash_state); + Hasher::hash_step(hash_state); copylen += message_chunk_size; } @@ -248,12 +262,12 @@ struct SHAHash { } }; -struct SHA1Hash : SHAHash { +struct SHA1Hash : SHAHash { /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. */ - virtual void __device__ hash_step(sha_intermediate_data* hash_state) const + static void __device__ hash_step(sha_intermediate_data* hash_state) { sha_word_type A = hash_state->hash_value[0]; sha_word_type B = hash_state->hash_value[1]; From 67bf9af3aacdc16d75bef55c97914d82edcaf3a9 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 12:27:27 -0700 Subject: [PATCH 026/100] Use generic sha_hash function for SHA-1 (can be reused for SHA-256, SHA-512). --- cpp/src/hash/sha_hash.cu | 51 ++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 2711d626a06..eef07c60209 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -334,14 +334,29 @@ struct SHA1Hash : SHAHash } }; -std::unique_ptr sha1_hash(table_view const& input, - cudaStream_t stream, - rmm::mr::device_memory_resource* mr) +/** + * @brief Call a SHA-1 or SHA-2 hash function on a table view. + * + * @tparam Hasher The struct used for computing SHA hashes. + * + * @param input The input table. + * @param digest_size The digest size in bytes, used to allocate the string columns containing + * results. + * @param empty_result A string representing the expected result for empty inputs. + * @param stream CUDA stream on which memory may be allocated if the memory + * resource supports streams. + * @param mr Memory resource to use for the device memory allocation + * @return A new column with the computed hash function result. + */ +template +std::unique_ptr sha_hash(table_view const& input, + string_scalar const& empty_result, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) { if (input.num_columns() == 0 || input.num_rows() == 0) { - // Return the SHA-1 hash of a zero-length input. - const string_scalar string_160bit("da39a3ee5e6b4b0d3255bfef95601890afd80709"); - auto output = make_column_from_scalar(string_160bit, input.num_rows(), stream, mr); + // Return the hash of a zero-length input. + auto output = make_column_from_scalar(empty_result, input.num_rows(), stream, mr); return output; } @@ -349,16 +364,17 @@ std::unique_ptr sha1_hash(table_view const& input, // TODO: Accept single layer list columns holding those types. CUDF_EXPECTS( std::all_of(input.begin(), input.end(), [](auto col) { return sha_type_check(col.type()); }), - "SHA-1 unsupported column type"); + "SHA unsupported column type"); // Result column allocation and creation - auto begin = thrust::make_constant_iterator(40); + auto begin = thrust::make_constant_iterator(digest_size); auto offsets_column = cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), stream, mr); - auto chars_column = strings::detail::create_chars_child_column(input.num_rows() * 40, stream, mr); - auto chars_view = chars_column->mutable_view(); - auto d_chars = chars_view.data(); + auto chars_column = + strings::detail::create_chars_child_column(input.num_rows() * digest_size, stream, mr); + auto chars_view = chars_column->mutable_view(); + auto d_chars = chars_view.data(); rmm::device_buffer null_mask{0, stream, mr}; @@ -370,7 +386,7 @@ std::unique_ptr sha1_hash(table_view const& input, thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { sha1_intermediate_data hash_state; - SHA1Hash hasher = SHA1Hash{}; + Hasher hasher = Hasher{}; for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { cudf::type_dispatcher( @@ -381,13 +397,22 @@ std::unique_ptr sha1_hash(table_view const& input, &hash_state); } } - hasher.finalize(&hash_state, d_chars + (row_index * 40)); + hasher.finalize(&hash_state, d_chars + (row_index * digest_size)); }); return make_strings_column( input.num_rows(), std::move(offsets_column), std::move(chars_column), 0, std::move(null_mask)); } +std::unique_ptr sha1_hash(table_view const& input, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result("da39a3ee5e6b4b0d3255bfef95601890afd80709"); + size_type const digest_size = 40; + return sha_hash(input, empty_result, stream, mr); +} + std::unique_ptr sha256_hash(table_view const& input, bool truncate_output, cudaStream_t stream, From ead336ee3783fe947c8b38eb5a2fd905022d4694 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 17:46:46 -0700 Subject: [PATCH 027/100] Intermediate work on SHA-256. --- cpp/src/hash/hashing.cu | 8 +- cpp/src/hash/sha_hash.cu | 201 ++++++++++++++++++++++++-------- cpp/tests/hashing/hash_test.cpp | 3 +- 3 files changed, 160 insertions(+), 52 deletions(-) diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index ce7005c93e6..a5573e83ad5 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -119,12 +119,12 @@ std::unique_ptr hash(table_view const& input, return serial_murmur_hash3_32(input, seed, stream, mr); case (hash_id::HASH_SPARK_MURMUR3): return serial_murmur_hash3_32(input, seed, stream, mr); - case (hash_id::HASH_SHA1): - return sha1_hash(input, stream, mr); + case (hash_id::HASH_SHA1): return sha1_hash(input, stream, mr); + case (hash_id::HASH_SHA256): return sha256_hash(input, false, stream, mr); + case (hash_id::HASH_SHA512): + return sha512_hash(input, false, stream, mr); // case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); - // case (hash_id::HASH_SHA256): return sha256_base(input, false, stream, mr); // case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); - // case (hash_id::HASH_SHA512): return sha512_base(input, false, stream, mr); default: return nullptr; } diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index eef07c60209..ae60669ea19 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -44,6 +44,12 @@ CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) return __funnelshift_l(x, x, r); } +CUDA_DEVICE_CALLABLE uint32_t rotate_bits_right(uint32_t x, int8_t r) +{ + // Equivalent to (x >> r) | (x << (32 - r)) + return __funnelshift_r(x, x, r); +} + // Swap the endianness of a 32 bit value CUDA_DEVICE_CALLABLE uint32_t swap_endian(uint32_t x) { @@ -64,14 +70,10 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) } // namespace -template +template struct SHAHash { - // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = MessageChunkSize; // Number of bytes used for the message length static constexpr auto message_length_size = 8; - using sha_intermediate_data = IntermediateType; - using sha_word_type = WordType; /** * @brief Execute SHA on input data chunks. @@ -79,26 +81,27 @@ struct SHAHash { * This accepts arbitrary data, handles it as bytes, and calls the hash step * when the buffer is filled up to message_chunk_size bytes. */ - template - void CUDA_DEVICE_CALLABLE process(TKey const& key, sha_intermediate_data* hash_state) const + template + void CUDA_DEVICE_CALLABLE process(TKey const& key, + typename Hasher::sha_intermediate_data* hash_state) const { uint32_t const len = sizeof(TKey); uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; - if (hash_state->buffer_length + len < message_chunk_size) { + if (hash_state->buffer_length + len < Hasher::message_chunk_size) { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { - uint32_t copylen = message_chunk_size - hash_state->buffer_length; + uint32_t copylen = Hasher::message_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); Hasher::hash_step(hash_state); - while (len > message_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); + while (len > Hasher::message_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, Hasher::message_chunk_size); Hasher::hash_step(hash_state); - copylen += message_chunk_size; + copylen += Hasher::message_chunk_size; } std::memcpy(hash_state->buffer, data + copylen, len - copylen); @@ -113,7 +116,9 @@ struct SHAHash { * the message length (in another step of the hash, if needed), and performs * the final hash step. */ - void CUDA_DEVICE_CALLABLE finalize(sha_intermediate_data* hash_state, char* result_location) + template + void CUDA_DEVICE_CALLABLE finalize(typename Hasher::sha_intermediate_data* hash_state, + char* result_location) { // Message length in bits. uint64_t const message_length_in_bits = (static_cast(hash_state->message_length)) @@ -135,13 +140,13 @@ struct SHAHash { constexpr auto message_length_supported_size = sizeof(message_length_in_bits); if (hash_state->buffer_length + message_length_size + end_of_message_size <= - message_chunk_size) { + Hasher::message_chunk_size) { // Fill the remainder of the buffer with zeros up to the space reserved // for the message length. The message length fits in this hash step. thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length + 1, - (message_chunk_size - message_length_supported_size - end_of_message_size - - hash_state->buffer_length), + (Hasher::message_chunk_size - message_length_supported_size - + end_of_message_size - hash_state->buffer_length), 0x00); } else { // Fill the remainder of the buffer with zeros. The message length doesn't @@ -149,28 +154,29 @@ struct SHAHash { // zeros followed by the message length. thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length + end_of_message_size, - (message_chunk_size - hash_state->buffer_length), + (Hasher::message_chunk_size - hash_state->buffer_length), 0x00); Hasher::hash_step(hash_state); thrust::fill_n( - thrust::seq, hash_state->buffer, message_chunk_size - message_length_size, 0x00); + thrust::seq, hash_state->buffer, Hasher::message_chunk_size - message_length_size, 0x00); } // Convert the 64-bit message length from little-endian to big-endian. uint64_t const full_length_flipped = swap_endian(message_length_in_bits); - std::memcpy(hash_state->buffer + message_chunk_size - message_length_supported_size, + std::memcpy(hash_state->buffer + Hasher::message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), message_length_supported_size); Hasher::hash_step(hash_state); + auto constexpr num_words = Hasher::digest_size / sizeof(typename Hasher::sha_word_type); #pragma unroll - for (int i = 0; i < 5; i++) { + for (int i = 0; i < num_words; i++) { // Convert word representation from big-endian to little-endian. - sha_word_type flipped = swap_endian(hash_state->hash_value[i]); - if constexpr (std::is_same_v) { + typename Hasher::sha_word_type flipped = swap_endian(hash_state->hash_value[i]); + if constexpr (std::is_same_v) { uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { uint32_t low_bits = static_cast(flipped); uint32ToLowercaseHexString(low_bits, result_location + (16 * i)); uint32_t high_bits = static_cast(flipped >> 32); @@ -181,28 +187,33 @@ struct SHAHash { } }; - template ()>* = nullptr> + template ()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data* hash_state) const { cudf_assert(false && "SHA Unsupported chrono type column"); } template < typename T, + typename Hasher = HasherT, typename std::enable_if_t() && !std::is_same_v>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data* hash_state) const { cudf_assert(false && "SHA Unsupported non-fixed-width type column"); } - template ()>* = nullptr> + template ()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data* hash_state) const { T const& key = col.element(row_index); if (isnan(key)) { @@ -216,26 +227,29 @@ struct SHAHash { } template () && !is_floating_point() && !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data* hash_state) const { process(col.element(row_index), hash_state); } - template >* = nullptr> + template >* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data* hash_state) const { string_view key = col.element(row_index); uint32_t const len = static_cast(key.size_bytes()); uint8_t const* data = reinterpret_cast(key.data()); hash_state->message_length += len; - if (hash_state->buffer_length + len < message_chunk_size) { + if (hash_state->buffer_length + len < Hasher::message_chunk_size) { // If the buffer will not be filled by this data, we copy the new data into // the buffer but do not trigger a hash step yet. std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); @@ -243,15 +257,15 @@ struct SHAHash { } else { // The buffer will be filled by this data. Copy a chunk of the data to fill // the buffer and trigger a hash step. - uint32_t copylen = message_chunk_size - hash_state->buffer_length; + uint32_t copylen = Hasher::message_chunk_size - hash_state->buffer_length; std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); Hasher::hash_step(hash_state); // Take buffer-sized chunks of the data and do a hash step on each chunk. - while (len > message_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, message_chunk_size); + while (len > Hasher::message_chunk_size + copylen) { + std::memcpy(hash_state->buffer, data + copylen, Hasher::message_chunk_size); Hasher::hash_step(hash_state); - copylen += message_chunk_size; + copylen += Hasher::message_chunk_size; } // The remaining data chunk does not fill the buffer. We copy the data into @@ -262,7 +276,16 @@ struct SHAHash { } }; -struct SHA1Hash : SHAHash { +struct SHA1Hash : SHAHash { + // Intermediate data type storing the hash state + using sha_intermediate_data = sha1_intermediate_data; + // The word type used by this hash function + using sha_word_type = sha1_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes + static constexpr auto digest_size = 40; + /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -334,13 +357,94 @@ struct SHA1Hash : SHAHash } }; +struct SHA256Hash : SHAHash { + using sha_intermediate_data = sha256_intermediate_data; + using sha_word_type = sha256_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes + static constexpr auto digest_size = 64; + + /** + * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + static void __device__ hash_step(sha_intermediate_data* hash_state) + { + sha_word_type A = hash_state->hash_value[0]; + sha_word_type B = hash_state->hash_value[1]; + sha_word_type C = hash_state->hash_value[2]; + sha_word_type D = hash_state->hash_value[3]; + sha_word_type E = hash_state->hash_value[4]; + sha_word_type F = hash_state->hash_value[5]; + sha_word_type G = hash_state->hash_value[6]; + sha_word_type H = hash_state->hash_value[7]; + + sha_word_type words[64]; + + // Word size in bytes + constexpr auto word_size = sizeof(sha_word_type); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + sha_word_type buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } + + // The rest of the 64 words are generated from the first 16 words. + for (int i = 16; i < 64; i++) { + sha_word_type s0 = rotate_bits_right(words[i - 15], 7) ^ + rotate_bits_right(words[i - 15], 18) ^ (words[i - 15] >> 3); + sha_word_type s1 = rotate_bits_right(words[i - 2], 17) ^ rotate_bits_right(words[i - 2], 19) ^ + (words[i - 2] >> 10); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } + + for (int i = 0; i < 64; i++) { + sha_word_type const s1 = + rotate_bits_right(E, 6) ^ rotate_bits_right(E, 11) ^ rotate_bits_right(E, 25); + sha_word_type const ch = (E & F) ^ ((~E) & G); + sha_word_type const temp1 = H + s1 + ch + sha256_hash_constants[i] + words[i]; + sha_word_type const s0 = + rotate_bits_right(A, 2) ^ rotate_bits_right(A, 13) ^ rotate_bits_right(A, 22); + sha_word_type const maj = (A & B) ^ (A & C) ^ (B & C); + sha_word_type const temp2 = s0 + maj; + + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + for (int i = 0; i < 8; i++) { + hash_state->hash_value[i] = words[i]; + } + + // hash_state->hash_value[0] += A; + // hash_state->hash_value[1] += B; + // hash_state->hash_value[2] += C; + // hash_state->hash_value[3] += D; + // hash_state->hash_value[4] += E; + // hash_state->hash_value[5] += F; + // hash_state->hash_value[6] += G; + // hash_state->hash_value[7] += H; + + hash_state->buffer_length = 0; + } +}; + /** * @brief Call a SHA-1 or SHA-2 hash function on a table view. * * @tparam Hasher The struct used for computing SHA hashes. * * @param input The input table. - * @param digest_size The digest size in bytes, used to allocate the string columns containing * results. * @param empty_result A string representing the expected result for empty inputs. * @param stream CUDA stream on which memory may be allocated if the memory @@ -348,7 +452,7 @@ struct SHA1Hash : SHAHash * @param mr Memory resource to use for the device memory allocation * @return A new column with the computed hash function result. */ -template +template std::unique_ptr sha_hash(table_view const& input, string_scalar const& empty_result, cudaStream_t stream, @@ -367,12 +471,12 @@ std::unique_ptr sha_hash(table_view const& input, "SHA unsupported column type"); // Result column allocation and creation - auto begin = thrust::make_constant_iterator(digest_size); + auto begin = thrust::make_constant_iterator(Hasher::digest_size); auto offsets_column = cudf::strings::detail::make_offsets_child_column(begin, begin + input.num_rows(), stream, mr); auto chars_column = - strings::detail::create_chars_child_column(input.num_rows() * digest_size, stream, mr); + strings::detail::create_chars_child_column(input.num_rows() * Hasher::digest_size, stream, mr); auto chars_view = chars_column->mutable_view(); auto d_chars = chars_view.data(); @@ -385,7 +489,7 @@ std::unique_ptr sha_hash(table_view const& input, thrust::make_counting_iterator(0), thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { - sha1_intermediate_data hash_state; + typename Hasher::sha_intermediate_data hash_state; Hasher hasher = Hasher{}; for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { @@ -397,7 +501,7 @@ std::unique_ptr sha_hash(table_view const& input, &hash_state); } } - hasher.finalize(&hash_state, d_chars + (row_index * digest_size)); + hasher.finalize(&hash_state, d_chars + (row_index * Hasher::digest_size)); }); return make_strings_column( @@ -409,8 +513,7 @@ std::unique_ptr sha1_hash(table_view const& input, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result("da39a3ee5e6b4b0d3255bfef95601890afd80709"); - size_type const digest_size = 40; - return sha_hash(input, empty_result, stream, mr); + return sha_hash(input, empty_result, stream, mr); } std::unique_ptr sha256_hash(table_view const& input, @@ -418,7 +521,9 @@ std::unique_ptr sha256_hash(table_view const& input, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { - return nullptr; + string_scalar const empty_result( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + return sha_hash(input, empty_result, stream, mr); } std::unique_ptr sha512_hash(table_view const& input, @@ -426,6 +531,10 @@ std::unique_ptr sha512_hash(table_view const& input, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { + string_scalar const empty_result( + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec" + "2f63b931bd47417a81a538327af927da3e"); + // return sha_hash(input, empty_result, stream, mr); return nullptr; } diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index cc2fe17bf4a..2322774b882 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -780,8 +780,7 @@ TEST_F(SHA1HashTest, MultiValueNulls) {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the " - "hash function being tested. This string needed to be longer.", + "the hash function being tested. This string needed to be longer.", "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); From 5867ebf4fc10665ca2946420a79e00e1d778cae0 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 20:32:22 -0700 Subject: [PATCH 028/100] Fix bugs in SHA-256 implementation (uninitialized hash constants, incorrect types/sizes.) --- cpp/src/hash/hash_constants.hpp | 3 ++- cpp/src/hash/sha_hash.cu | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index 458d4fc54b6..777cdef2411 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -75,7 +75,8 @@ using sha256_word_type = uint32_t; struct sha256_intermediate_data { uint64_t message_length = 0; uint32_t buffer_length = 0; - uint32_t hash_value[8]; + uint32_t hash_value[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint8_t buffer[64]; }; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index ae60669ea19..b5fafa07372 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -169,14 +170,15 @@ struct SHAHash { message_length_supported_size); Hasher::hash_step(hash_state); - auto constexpr num_words = Hasher::digest_size / sizeof(typename Hasher::sha_word_type); + // Each byte in the word generates two bytes in the hexadecimal string digest. + auto constexpr num_words = Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); #pragma unroll for (int i = 0; i < num_words; i++) { // Convert word representation from big-endian to little-endian. typename Hasher::sha_word_type flipped = swap_endian(hash_state->hash_value[i]); if constexpr (std::is_same_v) { uint32ToLowercaseHexString(flipped, result_location + (8 * i)); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { uint32_t low_bits = static_cast(flipped); uint32ToLowercaseHexString(low_bits, result_location + (16 * i)); uint32_t high_bits = static_cast(flipped >> 32); @@ -422,18 +424,14 @@ struct SHA256Hash : SHAHash { A = temp1 + temp2; } - for (int i = 0; i < 8; i++) { - hash_state->hash_value[i] = words[i]; - } - - // hash_state->hash_value[0] += A; - // hash_state->hash_value[1] += B; - // hash_state->hash_value[2] += C; - // hash_state->hash_value[3] += D; - // hash_state->hash_value[4] += E; - // hash_state->hash_value[5] += F; - // hash_state->hash_value[6] += G; - // hash_state->hash_value[7] += H; + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + hash_state->hash_value[5] += F; + hash_state->hash_value[6] += G; + hash_state->hash_value[7] += H; hash_state->buffer_length = 0; } From c94dc8c714f252a7ca1f2cfc18cfc401399ed13f Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 20:40:19 -0700 Subject: [PATCH 029/100] Add SHA-256 tests. --- cpp/tests/hashing/hash_test.cpp | 165 ++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 2322774b882..a953c9a43b4 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -877,4 +877,169 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) expect_columns_equal(output1->view(), output2->view()); } +class SHA256HashTest : public cudf::test::BaseFixture { +}; + +TEST_F(SHA256HashTest, MultiValue) +{ + strings_column_wrapper const strings_col( + {"", + "0", + "A 56 character string to test message padding algorithm.", + "A 63 character string to test message padding algorithm, again.", + "A 64 character string to test message padding algorithm, again!!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); + + strings_column_wrapper const sha256_string_results1( + {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9", + "d16883c666112142c1d72c9080b41161be7563250539e3f6ab6e2fdf2210074b", + "11174fa180460f5d683c2e63fcdd897dcbf10c28a9225d3ced9a8bbc3774415d", + "10a7d211e692c6f71bb9f7524ba1437588c2797356f05fc585340f002fe7015e", + "339d610dcb030bb4222bcf18c8ab82d911bfe7fb95b2cd9f6785fd4562b02401", + "2ce9936a4a2234bf8a76c37d92e01d549d03949792242e7f8a1ad68575e4e4a8", + "255fdd4d80a72f67921eb36f3e1157ea3e995068cee80e430c034e0d3692f614"}); + + strings_column_wrapper const sha256_string_results2( + {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "f1534392279bddbf9d43dde8701cb5be14b82f76ec6607bf8d6ad557f60f304e", + "96c204fa5d44b2487abfec105a05f8ae634551604f6596202ca99e3724e3953a", + "2e7be264f3ecbb2930e7c54bf6c5fc1f310a8c63c50916bb713f34699ed11719", + "224e4dce71d5dbd5e79ba65aaced7ad9c4f45dda146278087b2b61d164f056f0", + "91f3108d4e9c696fdb37ae49fdc6a2237f1d1f977b7216406cc8a6365355f43b", + "490be480afe271685e9c1fdf46daac0b9bf7f25602e153ca92a0ddb0e4b662ef", + "4ddc45855d7ce3ab09efacff1fbafb33502f7dd468dc5a62826689c1c658dbce"}); + + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col( + {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); + + // Different truth values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const sha256_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA256); + auto const sha256_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA256); + EXPECT_EQ(string_input1.num_rows(), sha256_string_output1->size()); + EXPECT_EQ(string_input2.num_rows(), sha256_string_output2->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_string_output1->view(), sha256_string_results1); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_string_output2->view(), sha256_string_results2); + + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const sha256_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); + auto const sha256_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + EXPECT_EQ(input1.num_rows(), sha256_output1->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_output1->view(), sha256_output2->view()); +} + +TEST_F(SHA256HashTest, MultiValueNulls) +{ + // Nulls with different values should be equal + strings_column_wrapper const strings_col1( + {"", + "Different but null!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, + {1, 0, 0, 1, 0}); + strings_column_wrapper const strings_col2({"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 1}); // empty string is equivalent to null + + // Nulls with different values should be equal + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + + // Nulls with different values should be equal + // Different truthy values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + + auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); + auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA256HashTestTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA256HashTestTyped, cudf::test::NumericTypes); + +TYPED_TEST(SHA256HashTestTyped, Equality) +{ + fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + auto const input = cudf::table_view({col}); + + // Hash of same input should be equal + auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA256); + auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA256); + + EXPECT_EQ(input.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +TYPED_TEST(SHA256HashTestTyped, EqualityNulls) +{ + using T = TypeParam; + + // Nulls with different values should be equal + fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA256HashTestFloatTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA256HashTestFloatTyped, cudf::test::FloatingPointTypes); + +TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) +{ + using T = TypeParam; + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + T nan = std::numeric_limits::quiet_NaN(); + T inf = std::numeric_limits::infinity(); + + fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + fixed_width_column_wrapper const col2( + {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + + expect_columns_equal(output1->view(), output2->view()); +} + CUDF_TEST_PROGRAM_MAIN() From 33878d183fb2aea23837e1d50de479523f6ca51c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 14 Sep 2021 21:21:20 -0700 Subject: [PATCH 030/100] Add SHA-512 draft (one failing test). --- cpp/src/hash/hash_constants.hpp | 9 +- cpp/src/hash/sha_hash.cu | 90 +++++++++++++++- cpp/tests/hashing/hash_test.cpp | 181 ++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 5 deletions(-) diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index 777cdef2411..b71a774e12a 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -100,7 +100,14 @@ using sha512_word_type = uint64_t; struct sha512_intermediate_data { uint64_t message_length = 0; uint32_t buffer_length = 0; - uint64_t hash_value[8]; + uint64_t hash_value[8] = {0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179}; uint8_t buffer[128]; }; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index b5fafa07372..c570038a4ea 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -41,16 +41,21 @@ bool sha_type_check(data_type dt) CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) { - // Equivalent to (x << r) | (x >> (32 - r)) + // This function is equivalent to (x << r) | (x >> (32 - r)) return __funnelshift_l(x, x, r); } CUDA_DEVICE_CALLABLE uint32_t rotate_bits_right(uint32_t x, int8_t r) { - // Equivalent to (x >> r) | (x << (32 - r)) + // This function is equivalent to (x >> r) | (x << (32 - r)) return __funnelshift_r(x, x, r); } +CUDA_DEVICE_CALLABLE uint64_t rotate_bits_right(uint64_t x, int8_t r) +{ + return (x >> r) | (x << (64 - r)); +} + // Swap the endianness of a 32 bit value CUDA_DEVICE_CALLABLE uint32_t swap_endian(uint32_t x) { @@ -437,6 +442,84 @@ struct SHA256Hash : SHAHash { } }; +struct SHA512Hash : SHAHash { + using sha_intermediate_data = sha512_intermediate_data; + using sha_word_type = sha512_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 128; + // Digest size in bytes + static constexpr auto digest_size = 128; + + /** + * @brief Core SHA-512 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ + static void __device__ hash_step(sha_intermediate_data* hash_state) + { + sha_word_type A = hash_state->hash_value[0]; + sha_word_type B = hash_state->hash_value[1]; + sha_word_type C = hash_state->hash_value[2]; + sha_word_type D = hash_state->hash_value[3]; + sha_word_type E = hash_state->hash_value[4]; + sha_word_type F = hash_state->hash_value[5]; + sha_word_type G = hash_state->hash_value[6]; + sha_word_type H = hash_state->hash_value[7]; + + sha_word_type words[80]; + + // Word size in bytes + constexpr auto word_size = sizeof(sha_word_type); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + sha_word_type buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } + + // The rest of the 80 words are generated from the first 16 words. + for (int i = 16; i < 80; i++) { + sha_word_type s0 = rotate_bits_right(words[i - 15], 1) ^ rotate_bits_right(words[i - 15], 8) ^ + (words[i - 15] >> 7); + sha_word_type s1 = rotate_bits_right(words[i - 2], 19) ^ rotate_bits_right(words[i - 2], 61) ^ + (words[i - 2] >> 6); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } + + for (int i = 0; i < 80; i++) { + sha_word_type const s1 = + rotate_bits_right(E, 14) ^ rotate_bits_right(E, 18) ^ rotate_bits_right(E, 41); + sha_word_type const ch = (E & F) ^ ((~E) & G); + sha_word_type const temp1 = H + s1 + ch + sha512_hash_constants[i] + words[i]; + sha_word_type const s0 = + rotate_bits_right(A, 28) ^ rotate_bits_right(A, 34) ^ rotate_bits_right(A, 39); + sha_word_type const maj = (A & B) ^ (A & C) ^ (B & C); + sha_word_type const temp2 = s0 + maj; + + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + hash_state->hash_value[5] += F; + hash_state->hash_value[6] += G; + hash_state->hash_value[7] += H; + + hash_state->buffer_length = 0; + } +}; + /** * @brief Call a SHA-1 or SHA-2 hash function on a table view. * @@ -532,8 +615,7 @@ std::unique_ptr sha512_hash(table_view const& input, string_scalar const empty_result( "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec" "2f63b931bd47417a81a538327af927da3e"); - // return sha_hash(input, empty_result, stream, mr); - return nullptr; + return sha_hash(input, empty_result, stream, mr); } } // namespace detail diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index a953c9a43b4..cf1740d9795 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -1042,4 +1042,185 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) expect_columns_equal(output1->view(), output2->view()); } +class SHA512HashTest : public cudf::test::BaseFixture { +}; + +TEST_F(SHA512HashTest, MultiValue) +{ + strings_column_wrapper const strings_col( + {"", + "0", + "A 56 character string to test message padding algorithm.", + "A 63 character string to test message padding algorithm, again.", + "A 64 character string to test message padding algorithm, again!!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); + + strings_column_wrapper const sha512_string_results1( + {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" + "c2f63b931bd47417a81a538327af927da3e", + "31bca02094eb78126a517b206a88c73cfa9ec6f704c7030d18212cace820f025f00bf0ea68dbf3f3a5436ca63b53b" + "f7bf80ad8d5de7d8359d0b7fed9dbc3ab99", + "1d8b355dbe0c4ad81c9815a1490f0b6a6fa710e42ca60767ffd6d845acd116defe307c9496a80c4a67653873af6ed" + "83e2e04c2102f55f9cd402677b246832e4c", + "8ac8ae9de5597aa630f071f81fcb94dc93b6a8f92d8f2cdd5a469764a5daf6ef387b6465ae097dcd6e0c64286260d" + "cc3d2c789d2cf5960df648c78a765e6c27c", + "9c436e24be60e17425a1a829642d97e7180b57485cf95db007cf5b32bbae1f2325b6874b3377e37806b15b739bffa" + "412ea6d095b726487d70e7b50e92d56c750", + "6a25ca1f20f6e79faea2a0770075e4262beb66b40f59c22d3e8abdb6188ef8d8914faf5dbf6df76165bb61b81dfda" + "46643f0d6366a39f7bd3d270312f9d3cf87", + "bae9eb4b5c05a4c5f85750b70b2f0ce78e387f992f0927a017eb40bd180a13004f6252a6bbf9816f195fb7d86668c" + "393dc0985aaf7168f48e8b905f3b9b02df2", + "05a4ca1c523dcab32edb7d8793934a4cdf41a9062b229d711f5326e297bda83fa965118b9d7636172b43688e8e149" + "008b3f967f1a969962b7e959af894a8a315"}); + + strings_column_wrapper const sha512_string_results2( + {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" + "c2f63b931bd47417a81a538327af927da3e", + "8ab3361c051a97ddc3c665d29f2762f8ac4240d08995f8724b6d07d8cbedd32c28f589ccdae514f20a6c8eea6f755" + "408dd3dd6837d66932ca2352eaeab594427", + "338b22eb841420affff9904f903ed14c91bf8f4d1b10f25c145a31018367607a2cf562121ba7eaa2d08db3382cc82" + "149805198c1fa3e7dc714fc2782e0f6ebd8", + "d3045ecde16ea036d2f2ff3fa685beb46d5fcb73de71f0aee653265f18b22e4c131255e6eb5ad3be2f32914408ec6" + "67911b49d951714decbdbfca1957be8ba10", + "da7706221f8861ef522ab9555f57306382fb18c337536545d839e431dede4ff9f9affafb82ab5588734a8fc6631e6" + "a0cd864634b62e24a42755c863c5d5c5848", + "04dadc8fdf205fe535c8eb38f20882fc2a0e308081052d7588e74f6620aa207749039468c126db7407050def80415" + "1d037cb188d5d4d459015032972a9e9f001", + "aae2e742074847889a029a8d3170f9e17177d48ec0b9dabe572aa68dd3001af0c512f164ba84aa75b13950948170a" + "0912912d16c98d2f05cb633c0d5b6a9105e", + "77f46e99a7a51ac04b4380ebca70c0782381629f711169a3b9dad3fc9aa6221a9c0cdaa9b9ea4329773e773e2987c" + "d1eebe0661386909684927d67819a2cf736"}); + + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col( + {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); + + // Different truth values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const sha512_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA512); + auto const sha512_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA512); + EXPECT_EQ(string_input1.num_rows(), sha512_string_output1->size()); + EXPECT_EQ(string_input2.num_rows(), sha512_string_output2->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_string_output1->view(), sha512_string_results1, verbosity); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_string_output2->view(), sha512_string_results2, verbosity); + + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const sha512_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); + auto const sha512_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + EXPECT_EQ(input1.num_rows(), sha512_output1->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_output1->view(), sha512_output2->view(), verbosity); +} + +TEST_F(SHA512HashTest, MultiValueNulls) +{ + // Nulls with different values should be equal + strings_column_wrapper const strings_col1( + {"", + "Different but null!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, + {1, 0, 0, 1, 0}); + strings_column_wrapper const strings_col2({"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 1}); // empty string is equivalent to null + + // Nulls with different values should be equal + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + + // Nulls with different values should be equal + // Different truthy values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + + auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); + auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA512HashTestTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA512HashTestTyped, cudf::test::NumericTypes); + +TYPED_TEST(SHA512HashTestTyped, Equality) +{ + fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + auto const input = cudf::table_view({col}); + + // Hash of same input should be equal + auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA512); + auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA512); + + EXPECT_EQ(input.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +TYPED_TEST(SHA512HashTestTyped, EqualityNulls) +{ + using T = TypeParam; + + // Nulls with different values should be equal + fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA512HashTestFloatTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA512HashTestFloatTyped, cudf::test::FloatingPointTypes); + +TYPED_TEST(SHA512HashTestFloatTyped, TestExtremes) +{ + using T = TypeParam; + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + T nan = std::numeric_limits::quiet_NaN(); + T inf = std::numeric_limits::infinity(); + + fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + fixed_width_column_wrapper const col2( + {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + + expect_columns_equal(output1->view(), output2->view()); +} + CUDF_TEST_PROGRAM_MAIN() From 7abc5aceebf0de01d95229ed661740fcfd8cd076 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 15 Sep 2021 18:51:58 -0700 Subject: [PATCH 031/100] Fix bug in message finalization. --- cpp/src/hash/sha_hash.cu | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c570038a4ea..e38e0881f43 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -78,9 +79,6 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) template struct SHAHash { - // Number of bytes used for the message length - static constexpr auto message_length_size = 8; - /** * @brief Execute SHA on input data chunks. * @@ -145,27 +143,30 @@ struct SHAHash { // bits. We always pad the upper 64 bits with zeros. constexpr auto message_length_supported_size = sizeof(message_length_in_bits); - if (hash_state->buffer_length + message_length_size + end_of_message_size <= + if (hash_state->buffer_length + Hasher::message_length_size + end_of_message_size <= Hasher::message_chunk_size) { // Fill the remainder of the buffer with zeros up to the space reserved // for the message length. The message length fits in this hash step. - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + 1, - (Hasher::message_chunk_size - message_length_supported_size - - end_of_message_size - hash_state->buffer_length), - 0x00); + thrust::fill(thrust::seq, + hash_state->buffer + hash_state->buffer_length + end_of_message_size, + hash_state->buffer + Hasher::message_chunk_size - message_length_supported_size, + 0x00); } else { // Fill the remainder of the buffer with zeros. The message length doesn't // fit and will be processed in a subsequent hash step comprised of only // zeros followed by the message length. - thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length + end_of_message_size, - (Hasher::message_chunk_size - hash_state->buffer_length), - 0x00); + thrust::fill(thrust::seq, + hash_state->buffer + hash_state->buffer_length + end_of_message_size, + hash_state->buffer + Hasher::message_chunk_size, + 0x00); Hasher::hash_step(hash_state); - thrust::fill_n( - thrust::seq, hash_state->buffer, Hasher::message_chunk_size - message_length_size, 0x00); + // Fill the entire message with zeros up to the final bytes reserved for + // the message length. + thrust::fill_n(thrust::seq, + hash_state->buffer, + Hasher::message_chunk_size - message_length_supported_size, + 0x00); } // Convert the 64-bit message length from little-endian to big-endian. @@ -292,6 +293,8 @@ struct SHA1Hash : SHAHash { static constexpr auto message_chunk_size = 64; // Digest size in bytes static constexpr auto digest_size = 40; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, @@ -371,6 +374,8 @@ struct SHA256Hash : SHAHash { static constexpr auto message_chunk_size = 64; // Digest size in bytes static constexpr auto digest_size = 64; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; /** * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, @@ -449,6 +454,8 @@ struct SHA512Hash : SHAHash { static constexpr auto message_chunk_size = 128; // Digest size in bytes static constexpr auto digest_size = 128; + // Number of bytes used for the message length + static constexpr auto message_length_size = 16; /** * @brief Core SHA-512 algorithm implementation. Processes a single 512-bit chunk, @@ -541,6 +548,7 @@ std::unique_ptr sha_hash(table_view const& input, { if (input.num_columns() == 0 || input.num_rows() == 0) { // Return the hash of a zero-length input. + // TODO: This probably needs tested! auto output = make_column_from_scalar(empty_result, input.num_rows(), stream, mr); return output; } @@ -559,7 +567,7 @@ std::unique_ptr sha_hash(table_view const& input, auto chars_column = strings::detail::create_chars_child_column(input.num_rows() * Hasher::digest_size, stream, mr); auto chars_view = chars_column->mutable_view(); - auto d_chars = chars_view.data(); + auto d_chars = chars_view.template data(); rmm::device_buffer null_mask{0, stream, mr}; From a89f34cbca4dacedbffb4e28009952026a6c5644 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 15 Sep 2021 21:14:42 -0700 Subject: [PATCH 032/100] Draft of SHA-224, SHA-384. --- cpp/include/cudf/detail/hashing.hpp | 12 ++++++-- cpp/src/hash/hash_constants.hpp | 45 ++++++++++++++--------------- cpp/src/hash/hashing.cu | 10 +++---- cpp/src/hash/sha_hash.cu | 27 ++++++++++++++--- 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/cpp/include/cudf/detail/hashing.hpp b/cpp/include/cudf/detail/hashing.hpp index 9fdd142240d..9ec3013201f 100644 --- a/cpp/include/cudf/detail/hashing.hpp +++ b/cpp/include/cudf/detail/hashing.hpp @@ -58,15 +58,23 @@ std::unique_ptr sha1_hash( cudaStream_t stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha224_hash( + table_view const& input, + cudaStream_t stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + std::unique_ptr sha256_hash( table_view const& input, - bool truncate_output, + cudaStream_t stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +std::unique_ptr sha384_hash( + table_view const& input, cudaStream_t stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); std::unique_ptr sha512_hash( table_view const& input, - bool truncate_output, cudaStream_t stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index b71a774e12a..ff0486f3b51 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -80,6 +80,14 @@ struct sha256_intermediate_data { uint8_t buffer[64]; }; +struct sha224_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + uint8_t buffer[64]; +}; + __device__ __constant__ sha256_word_type sha256_hash_constants[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, @@ -89,11 +97,6 @@ __device__ __constant__ sha256_word_type sha256_hash_constants[64] = { 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; -__device__ __constant__ sha256_word_type sha224_initial_hash[8] = { - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; - -__device__ __constant__ sha256_word_type sha256_initial_hash[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; using sha512_word_type = uint64_t; @@ -111,6 +114,20 @@ struct sha512_intermediate_data { uint8_t buffer[128]; }; +struct sha384_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4}; + uint8_t buffer[128]; +}; + __device__ __constant__ sha512_word_type sha512_hash_constants[80] = { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, @@ -134,23 +151,5 @@ __device__ __constant__ sha512_word_type sha512_hash_constants[80] = { 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -__device__ __constant__ sha512_word_type sha384_initial_hash[8] = {0xcbbb9d5dc1059ed8, - 0x629a292a367cd507, - 0x9159015a3070dd17, - 0x152fecd8f70e5939, - 0x67332667ffc00b31, - 0x8eb44a8768581511, - 0xdb0c2e0d64f98fa7, - 0x47b5481dbefa4fa4}; - -__device__ __constant__ sha512_word_type sha512_initial_hash[8] = {0x6a09e667f3bcc908, - 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, - 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, - 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, - 0x5be0cd19137e2179}; - } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index a5573e83ad5..f1670fadc41 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -120,12 +120,10 @@ std::unique_ptr hash(table_view const& input, case (hash_id::HASH_SPARK_MURMUR3): return serial_murmur_hash3_32(input, seed, stream, mr); case (hash_id::HASH_SHA1): return sha1_hash(input, stream, mr); - case (hash_id::HASH_SHA256): return sha256_hash(input, false, stream, mr); - case (hash_id::HASH_SHA512): - return sha512_hash(input, false, stream, mr); - // case (hash_id::HASH_SHA224): return sha256_base(input, true, stream, mr); - // case (hash_id::HASH_SHA384): return sha512_base(input, true, stream, mr); - + case (hash_id::HASH_SHA224): return sha224_hash(input, stream, mr); + case (hash_id::HASH_SHA256): return sha256_hash(input, stream, mr); + case (hash_id::HASH_SHA384): return sha384_hash(input, stream, mr); + case (hash_id::HASH_SHA512): return sha512_hash(input, stream, mr); default: return nullptr; } } diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index e38e0881f43..28e36c2f9c7 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -177,9 +177,11 @@ struct SHAHash { Hasher::hash_step(hash_state); // Each byte in the word generates two bytes in the hexadecimal string digest. - auto constexpr num_words = Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); + // SHA-224 and SHA-384 digests are truncated because their digest does not + // include all of the hash values. + auto constexpr num_words_to_copy = Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); #pragma unroll - for (int i = 0; i < num_words; i++) { + for (int i = 0; i < num_words_to_copy; i++) { // Convert word representation from big-endian to little-endian. typename Hasher::sha_word_type flipped = swap_endian(hash_state->hash_value[i]); if constexpr (std::is_same_v) { @@ -605,8 +607,17 @@ std::unique_ptr sha1_hash(table_view const& input, return sha_hash(input, empty_result, stream, mr); } +std::unique_ptr sha224_hash(table_view const& input, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result( + "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); + return nullptr; + // return sha_hash(input, empty_result, stream, mr); +} + std::unique_ptr sha256_hash(table_view const& input, - bool truncate_output, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { @@ -615,8 +626,16 @@ std::unique_ptr sha256_hash(table_view const& input, return sha_hash(input, empty_result, stream, mr); } +std::unique_ptr sha384_hash(table_view const& input, + cudaStream_t stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"); + return nullptr; + // return sha_hash(input, empty_result, stream, mr); +} + std::unique_ptr sha512_hash(table_view const& input, - bool truncate_output, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { From d9ecdfa68d58cc499264eaad2ee3b878779668e9 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 15 Sep 2021 21:23:11 -0700 Subject: [PATCH 033/100] Use explicit SHA word types, add implementations of SHA-224 and SHA-384. --- cpp/src/hash/sha_hash.cu | 330 ++++++++++++++++++++++----------------- 1 file changed, 188 insertions(+), 142 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 28e36c2f9c7..5077eb6bb81 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -179,7 +179,8 @@ struct SHAHash { // Each byte in the word generates two bytes in the hexadecimal string digest. // SHA-224 and SHA-384 digests are truncated because their digest does not // include all of the hash values. - auto constexpr num_words_to_copy = Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); + auto constexpr num_words_to_copy = + Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); #pragma unroll for (int i = 0; i < num_words_to_copy; i++) { // Convert word representation from big-endian to little-endian. @@ -304,20 +305,20 @@ struct SHA1Hash : SHAHash { */ static void __device__ hash_step(sha_intermediate_data* hash_state) { - sha_word_type A = hash_state->hash_value[0]; - sha_word_type B = hash_state->hash_value[1]; - sha_word_type C = hash_state->hash_value[2]; - sha_word_type D = hash_state->hash_value[3]; - sha_word_type E = hash_state->hash_value[4]; + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + uint32_t E = hash_state->hash_value[4]; - sha_word_type words[80]; + uint32_t words[80]; // Word size in bytes - constexpr auto word_size = sizeof(sha_word_type); + constexpr auto word_size = sizeof(uint32_t); // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { - sha_word_type buffer_element_as_int; + uint32_t buffer_element_as_int; std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); @@ -325,14 +326,14 @@ struct SHA1Hash : SHAHash { // The rest of the 80 words are generated from the first 16 words. for (int i = 16; i < 80; i++) { - sha_word_type temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = rotate_bits_left(temp, 1); + uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotate_bits_left(temp, 1); } for (int i = 0; i < 80; i++) { - sha_word_type F; - sha_word_type temp; - sha_word_type k; + uint32_t F; + uint32_t temp; + uint32_t k; switch (i / 20) { case 0: F = D ^ (B & (C ^ D)); @@ -369,6 +370,92 @@ struct SHA1Hash : SHAHash { } }; +/** + * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ +template +void __device__ sha256_hash_step(sha_intermediate_data* hash_state) +{ + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + uint32_t E = hash_state->hash_value[4]; + uint32_t F = hash_state->hash_value[5]; + uint32_t G = hash_state->hash_value[6]; + uint32_t H = hash_state->hash_value[7]; + + uint32_t words[64]; + + // Word size in bytes + constexpr auto word_size = sizeof(uint32_t); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } + + // The rest of the 64 words are generated from the first 16 words. + for (int i = 16; i < 64; i++) { + uint32_t s0 = rotate_bits_right(words[i - 15], 7) ^ rotate_bits_right(words[i - 15], 18) ^ + (words[i - 15] >> 3); + uint32_t s1 = rotate_bits_right(words[i - 2], 17) ^ rotate_bits_right(words[i - 2], 19) ^ + (words[i - 2] >> 10); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } + + for (int i = 0; i < 64; i++) { + uint32_t const s1 = + rotate_bits_right(E, 6) ^ rotate_bits_right(E, 11) ^ rotate_bits_right(E, 25); + uint32_t const ch = (E & F) ^ ((~E) & G); + uint32_t const temp1 = H + s1 + ch + sha256_hash_constants[i] + words[i]; + uint32_t const s0 = + rotate_bits_right(A, 2) ^ rotate_bits_right(A, 13) ^ rotate_bits_right(A, 22); + uint32_t const maj = (A & B) ^ (A & C) ^ (B & C); + uint32_t const temp2 = s0 + maj; + + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + hash_state->hash_value[5] += F; + hash_state->hash_value[6] += G; + hash_state->hash_value[7] += H; + + hash_state->buffer_length = 0; +} + +struct SHA224Hash : SHAHash { + using sha_intermediate_data = sha224_intermediate_data; + using sha_word_type = sha256_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes. This is truncated from SHA-256. + static constexpr auto digest_size = 56; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; + + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + { + sha256_hash_step(hash_state); + } +}; + struct SHA256Hash : SHAHash { using sha_intermediate_data = sha256_intermediate_data; using sha_word_type = sha256_word_type; @@ -379,73 +466,95 @@ struct SHA256Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - /** - * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - static void __device__ hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha_word_type A = hash_state->hash_value[0]; - sha_word_type B = hash_state->hash_value[1]; - sha_word_type C = hash_state->hash_value[2]; - sha_word_type D = hash_state->hash_value[3]; - sha_word_type E = hash_state->hash_value[4]; - sha_word_type F = hash_state->hash_value[5]; - sha_word_type G = hash_state->hash_value[6]; - sha_word_type H = hash_state->hash_value[7]; + sha256_hash_step(hash_state); + } +}; - sha_word_type words[64]; +/** + * @brief Core SHA-512 algorithm implementation. Processes a single 1024-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ +template +void __device__ sha512_hash_step(sha_intermediate_data* hash_state) +{ + uint64_t A = hash_state->hash_value[0]; + uint64_t B = hash_state->hash_value[1]; + uint64_t C = hash_state->hash_value[2]; + uint64_t D = hash_state->hash_value[3]; + uint64_t E = hash_state->hash_value[4]; + uint64_t F = hash_state->hash_value[5]; + uint64_t G = hash_state->hash_value[6]; + uint64_t H = hash_state->hash_value[7]; + + uint64_t words[80]; + + // Word size in bytes + constexpr auto word_size = sizeof(uint64_t); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + uint64_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } - // Word size in bytes - constexpr auto word_size = sizeof(sha_word_type); + // The rest of the 80 words are generated from the first 16 words. + for (int i = 16; i < 80; i++) { + uint64_t s0 = rotate_bits_right(words[i - 15], 1) ^ rotate_bits_right(words[i - 15], 8) ^ + (words[i - 15] >> 7); + uint64_t s1 = rotate_bits_right(words[i - 2], 19) ^ rotate_bits_right(words[i - 2], 61) ^ + (words[i - 2] >> 6); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } - // The 512-bit message buffer fills the first 16 words. - for (int i = 0; i < 16; i++) { - sha_word_type buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); - // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); - } + for (int i = 0; i < 80; i++) { + uint64_t const s1 = + rotate_bits_right(E, 14) ^ rotate_bits_right(E, 18) ^ rotate_bits_right(E, 41); + uint64_t const ch = (E & F) ^ ((~E) & G); + uint64_t const temp1 = H + s1 + ch + sha512_hash_constants[i] + words[i]; + uint64_t const s0 = + rotate_bits_right(A, 28) ^ rotate_bits_right(A, 34) ^ rotate_bits_right(A, 39); + uint64_t const maj = (A & B) ^ (A & C) ^ (B & C); + uint64_t const temp2 = s0 + maj; + + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } - // The rest of the 64 words are generated from the first 16 words. - for (int i = 16; i < 64; i++) { - sha_word_type s0 = rotate_bits_right(words[i - 15], 7) ^ - rotate_bits_right(words[i - 15], 18) ^ (words[i - 15] >> 3); - sha_word_type s1 = rotate_bits_right(words[i - 2], 17) ^ rotate_bits_right(words[i - 2], 19) ^ - (words[i - 2] >> 10); - words[i] = words[i - 16] + s0 + words[i - 7] + s1; - } + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + hash_state->hash_value[5] += F; + hash_state->hash_value[6] += G; + hash_state->hash_value[7] += H; - for (int i = 0; i < 64; i++) { - sha_word_type const s1 = - rotate_bits_right(E, 6) ^ rotate_bits_right(E, 11) ^ rotate_bits_right(E, 25); - sha_word_type const ch = (E & F) ^ ((~E) & G); - sha_word_type const temp1 = H + s1 + ch + sha256_hash_constants[i] + words[i]; - sha_word_type const s0 = - rotate_bits_right(A, 2) ^ rotate_bits_right(A, 13) ^ rotate_bits_right(A, 22); - sha_word_type const maj = (A & B) ^ (A & C) ^ (B & C); - sha_word_type const temp2 = s0 + maj; - - H = G; - G = F; - F = E; - E = D + temp1; - D = C; - C = B; - B = A; - A = temp1 + temp2; - } + hash_state->buffer_length = 0; +} - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; - hash_state->hash_value[5] += F; - hash_state->hash_value[6] += G; - hash_state->hash_value[7] += H; +struct SHA384Hash : SHAHash { + using sha_intermediate_data = sha384_intermediate_data; + using sha_word_type = sha512_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 128; + // Digest size in bytes. This is truncated from SHA-512. + static constexpr auto digest_size = 96; + // Number of bytes used for the message length + static constexpr auto message_length_size = 16; - hash_state->buffer_length = 0; + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + { + sha512_hash_step(hash_state); } }; @@ -459,73 +568,9 @@ struct SHA512Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 16; - /** - * @brief Core SHA-512 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - static void __device__ hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha_word_type A = hash_state->hash_value[0]; - sha_word_type B = hash_state->hash_value[1]; - sha_word_type C = hash_state->hash_value[2]; - sha_word_type D = hash_state->hash_value[3]; - sha_word_type E = hash_state->hash_value[4]; - sha_word_type F = hash_state->hash_value[5]; - sha_word_type G = hash_state->hash_value[6]; - sha_word_type H = hash_state->hash_value[7]; - - sha_word_type words[80]; - - // Word size in bytes - constexpr auto word_size = sizeof(sha_word_type); - - // The 512-bit message buffer fills the first 16 words. - for (int i = 0; i < 16; i++) { - sha_word_type buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); - // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); - } - - // The rest of the 80 words are generated from the first 16 words. - for (int i = 16; i < 80; i++) { - sha_word_type s0 = rotate_bits_right(words[i - 15], 1) ^ rotate_bits_right(words[i - 15], 8) ^ - (words[i - 15] >> 7); - sha_word_type s1 = rotate_bits_right(words[i - 2], 19) ^ rotate_bits_right(words[i - 2], 61) ^ - (words[i - 2] >> 6); - words[i] = words[i - 16] + s0 + words[i - 7] + s1; - } - - for (int i = 0; i < 80; i++) { - sha_word_type const s1 = - rotate_bits_right(E, 14) ^ rotate_bits_right(E, 18) ^ rotate_bits_right(E, 41); - sha_word_type const ch = (E & F) ^ ((~E) & G); - sha_word_type const temp1 = H + s1 + ch + sha512_hash_constants[i] + words[i]; - sha_word_type const s0 = - rotate_bits_right(A, 28) ^ rotate_bits_right(A, 34) ^ rotate_bits_right(A, 39); - sha_word_type const maj = (A & B) ^ (A & C) ^ (B & C); - sha_word_type const temp2 = s0 + maj; - - H = G; - G = F; - F = E; - E = D + temp1; - D = C; - C = B; - B = A; - A = temp1 + temp2; - } - - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; - hash_state->hash_value[5] += F; - hash_state->hash_value[6] += G; - hash_state->hash_value[7] += H; - - hash_state->buffer_length = 0; + sha512_hash_step(hash_state); } }; @@ -611,8 +656,7 @@ std::unique_ptr sha224_hash(table_view const& input, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { - string_scalar const empty_result( - "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); + string_scalar const empty_result("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); return nullptr; // return sha_hash(input, empty_result, stream, mr); } @@ -630,7 +674,9 @@ std::unique_ptr sha384_hash(table_view const& input, cudaStream_t stream, rmm::mr::device_memory_resource* mr) { - string_scalar const empty_result("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"); + string_scalar const empty_result( + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b9" + "5b"); return nullptr; // return sha_hash(input, empty_result, stream, mr); } From cc683fca97f2eeeb5b4f3ea5da69f399403444ed Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 15 Sep 2021 22:04:19 -0700 Subject: [PATCH 034/100] Enable SHA-224, SHA-384. --- cpp/src/hash/sha_hash.cu | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 5077eb6bb81..b19995dd366 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -657,8 +657,7 @@ std::unique_ptr sha224_hash(table_view const& input, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); - return nullptr; - // return sha_hash(input, empty_result, stream, mr); + return sha_hash(input, empty_result, stream, mr); } std::unique_ptr sha256_hash(table_view const& input, @@ -677,8 +676,7 @@ std::unique_ptr sha384_hash(table_view const& input, string_scalar const empty_result( "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b9" "5b"); - return nullptr; - // return sha_hash(input, empty_result, stream, mr); + return sha_hash(input, empty_result, stream, mr); } std::unique_ptr sha512_hash(table_view const& input, From ad65b49e05725ec03da8c8a5c98f85fddfc2cf23 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 15 Sep 2021 22:05:09 -0700 Subject: [PATCH 035/100] Add tests for SHA-224, SHA-384. --- cpp/tests/hashing/hash_test.cpp | 346 ++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index cf1740d9795..999baa955af 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -877,6 +877,171 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) expect_columns_equal(output1->view(), output2->view()); } +class SHA224HashTest : public cudf::test::BaseFixture { +}; + +TEST_F(SHA224HashTest, MultiValue) +{ + strings_column_wrapper const strings_col( + {"", + "0", + "A 56 character string to test message padding algorithm.", + "A 63 character string to test message padding algorithm, again.", + "A 64 character string to test message padding algorithm, again!!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); + + strings_column_wrapper const sha224_string_results1( + {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "dfd5f9139a820075df69d7895015360b76d0360f3d4b77a845689614", + "5d1ed8373987e403482cefe1662a63fa3076c0a5331d141f41654bbe", + "0662c91000b99de7a20c89097dd62f59120398d52499497489ccff95", + "f9ea303770699483f3e53263b32a3b3c876d1b8808ce84df4b8ca1c4", + "2da6cd4bdaa0a99fd7236cd5507c52e12328e71192e83b32d2f110f9", + "e7d0adb165079efc6c6343112f8b154aa3644ca6326f658aaa0f8e4a", + "309cc09eaa051beea7d0b0159daca9b4e8a533cb554e8f382c82709e"}); + + strings_column_wrapper const sha224_string_results2( + {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "5538ae2b02d4ae0b7090dc908ca69cd11a2ffad43c7435f1dbad5e6a", + "8e1955a473a149368dc0a931f99379b44b0bb752f206dbdf68629232", + "8581001e08295b7884428c022378cfdd643c977aefe4512f0252dc30", + "d5854dfe3c32996345b103a6a16c7bdfa924723d620b150737e77370", + "dd56deac5f2caa579a440ee814fc04a3afaf805d567087ac3317beb3", + "14fb559f6309604bedd89183f585f3b433932b5b0e675848feebf8ec", + "d219eefea538491efcb69bc5bbef4177ad991d1b6e1367b5981b8c31"}); + + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col( + {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); + + // Different truth values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const sha224_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA224); + auto const sha224_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA224); + EXPECT_EQ(string_input1.num_rows(), sha224_string_output1->size()); + EXPECT_EQ(string_input2.num_rows(), sha224_string_output2->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_string_output1->view(), sha224_string_results1); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_string_output2->view(), sha224_string_results2); + + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const sha224_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); + auto const sha224_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + EXPECT_EQ(input1.num_rows(), sha224_output1->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_output1->view(), sha224_output2->view()); +} + +TEST_F(SHA224HashTest, MultiValueNulls) +{ + // Nulls with different values should be equal + strings_column_wrapper const strings_col1( + {"", + "Different but null!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, + {1, 0, 0, 1, 0}); + strings_column_wrapper const strings_col2({"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 1}); // empty string is equivalent to null + + // Nulls with different values should be equal + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + + // Nulls with different values should be equal + // Different truthy values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + + auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); + auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA224HashTestTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA224HashTestTyped, cudf::test::NumericTypes); + +TYPED_TEST(SHA224HashTestTyped, Equality) +{ + fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + auto const input = cudf::table_view({col}); + + // Hash of same input should be equal + auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA224); + auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA224); + + EXPECT_EQ(input.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +TYPED_TEST(SHA224HashTestTyped, EqualityNulls) +{ + using T = TypeParam; + + // Nulls with different values should be equal + fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA224HashTestFloatTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA224HashTestFloatTyped, cudf::test::FloatingPointTypes); + +TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) +{ + using T = TypeParam; + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + T nan = std::numeric_limits::quiet_NaN(); + T inf = std::numeric_limits::infinity(); + + fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + fixed_width_column_wrapper const col2( + {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + + expect_columns_equal(output1->view(), output2->view()); +} + class SHA256HashTest : public cudf::test::BaseFixture { }; @@ -1042,6 +1207,187 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) expect_columns_equal(output1->view(), output2->view()); } +class SHA384HashTest : public cudf::test::BaseFixture { +}; + +TEST_F(SHA384HashTest, MultiValue) +{ + strings_column_wrapper const strings_col( + {"", + "0", + "A 56 character string to test message padding algorithm.", + "A 63 character string to test message padding algorithm, again.", + "A 64 character string to test message padding algorithm, again!!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); + + strings_column_wrapper const sha384_string_results1( + {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" + "95b", + "5f91550edb03f0bb8917da57f0f8818976f5da971307b7ee4886bb951c4891a1f16f840dae8f655aa5df718884ebc" + "15b", + "982000cce895dc439edbcb7ba5b908cb5b7e939fe913d58506a486735a914b0dfbcebb02c33c428287baa0bfc7fe0" + "948", + "c3ea54e4d6d97c2a84dac9ac48ed9dd1a49118be880d8466044720cfdcd23427bf556f12204bb34ede29dbf207033" + "78c", + "5d7a853a18138fa90feac07c896dfca65a0f1eb2ed40f1fd7be6238dd7ef429bb1aeb0236735500eb954c9b4ba923" + "254", + "c72bcaf3a4b01986711cd5d2614aa8f9d7fad61455613eac4561b1468f9a25dd26566c8ad1190dec7567be4f6fc1d" + "b29", + "281826f23bebb3f835d2f15edcb0cdb3078ae2d7dc516f3a366af172dff4db6dd5833bc1e5ee411d52c598773e939" + "7b6", + "3a9d1a870a5f6a4c04df1daf1808163d33852897ebc757a5b028a1214fbc758485a392159b11bc360cfadc79f9512" + "822"}); + + strings_column_wrapper const sha384_string_results2( + {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" + "95b", + "34ae2cd40efabf896d8d4173e500278d10671b2d914efb5480e8349190bc7e8e1d532ad568d00a8295ea536a9b42b" + "bc6", + "e80c25efd8032ea94dad1509a68f9bf745ce1184b8a148714c28c7e0fae1100ab14057417394f83118eaa151e014d" + "917", + "69eaddc4ef2ed967fc6a86d3ed3777b2c2015df4cf8bbbf65681556f451a4a0ae805a89c2d56641b4422b5f248c56" + "77d", + "112a6f9c74741d490747db90f5e901a88b7a32f637c030d6d96e5f89a70a5f1ee209e018648842c0e1d32002f95fd" + "d07", + "dc6f24bb0eb2c96fb53c52c402f073de089f3aeae9594be0c4f4cb31b13bd48769b80aa97d83a25ece1edf0c83373" + "f56", + "781a33adfdcdcbb514318728c074fbb59d44002995825642e0c9bfef8a2ccf3fb637b39ff3dd265df8cd93c86e945" + "ce9", + "d2efb1591c4503f23c34ddb4da6bb1017d3d4d7c9f23ee6aa52e71c98d41060bc35eb22f41b6130d5c42a6e717fb3" + "edf"}); + + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col( + {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); + + // Different truth values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + + auto const string_input1 = cudf::table_view({strings_col}); + auto const string_input2 = cudf::table_view({strings_col, strings_col}); + auto const sha384_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA384); + auto const sha384_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA384); + EXPECT_EQ(string_input1.num_rows(), sha384_string_output1->size()); + EXPECT_EQ(string_input2.num_rows(), sha384_string_output2->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_string_output1->view(), sha384_string_results1, verbosity); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_string_output2->view(), sha384_string_results2, verbosity); + + auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); + auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); + auto const sha384_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); + auto const sha384_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + EXPECT_EQ(input1.num_rows(), sha384_output1->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_output1->view(), sha384_output2->view(), verbosity); +} + +TEST_F(SHA384HashTest, MultiValueNulls) +{ + // Nulls with different values should be equal + strings_column_wrapper const strings_col1( + {"", + "Different but null!", + "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " + "the hash function being tested. This string needed to be longer.", + "All work and no play makes Jack a dull boy", + "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, + {1, 0, 0, 1, 0}); + strings_column_wrapper const strings_col2({"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 1}); // empty string is equivalent to null + + // Nulls with different values should be equal + using limits = std::numeric_limits; + fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, + {1, 0, 0, 1, 1}); + + // Nulls with different values should be equal + // Different truthy values should be equal + fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + + auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); + auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA384HashTestTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA384HashTestTyped, cudf::test::NumericTypes); + +TYPED_TEST(SHA384HashTestTyped, Equality) +{ + fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + auto const input = cudf::table_view({col}); + + // Hash of same input should be equal + auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA384); + auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA384); + + EXPECT_EQ(input.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +TYPED_TEST(SHA384HashTestTyped, EqualityNulls) +{ + using T = TypeParam; + + // Nulls with different values should be equal + fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + + EXPECT_EQ(input1.num_rows(), output1->size()); + expect_columns_equal(output1->view(), output2->view()); +} + +template +class SHA384HashTestFloatTyped : public cudf::test::BaseFixture { +}; + +TYPED_TEST_CASE(SHA384HashTestFloatTyped, cudf::test::FloatingPointTypes); + +TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) +{ + using T = TypeParam; + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + T nan = std::numeric_limits::quiet_NaN(); + T inf = std::numeric_limits::infinity(); + + fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + fixed_width_column_wrapper const col2( + {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); + + auto const input1 = cudf::table_view({col1}); + auto const input2 = cudf::table_view({col2}); + + auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); + auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + + expect_columns_equal(output1->view(), output2->view()); +} + class SHA512HashTest : public cudf::test::BaseFixture { }; From f338217cf9c010e1c386bedb438878bee72e0e0b Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 16 Sep 2021 11:48:13 -0700 Subject: [PATCH 036/100] Use rmm::cuda_stream_view. --- cpp/include/cudf/detail/hashing.hpp | 10 +++++----- cpp/src/hash/sha_hash.cu | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/include/cudf/detail/hashing.hpp b/cpp/include/cudf/detail/hashing.hpp index 9ec3013201f..0a25825deae 100644 --- a/cpp/include/cudf/detail/hashing.hpp +++ b/cpp/include/cudf/detail/hashing.hpp @@ -55,27 +55,27 @@ std::unique_ptr serial_murmur_hash3_32( std::unique_ptr sha1_hash( table_view const& input, - cudaStream_t stream = rmm::cuda_stream_default, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); std::unique_ptr sha224_hash( table_view const& input, - cudaStream_t stream = rmm::cuda_stream_default, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); std::unique_ptr sha256_hash( table_view const& input, - cudaStream_t stream = rmm::cuda_stream_default, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); std::unique_ptr sha384_hash( table_view const& input, - cudaStream_t stream = rmm::cuda_stream_default, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); std::unique_ptr sha512_hash( table_view const& input, - cudaStream_t stream = rmm::cuda_stream_default, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); } // namespace detail diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index b19995dd366..d1e2566d434 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -590,7 +590,7 @@ struct SHA512Hash : SHAHash { template std::unique_ptr sha_hash(table_view const& input, string_scalar const& empty_result, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { if (input.num_columns() == 0 || input.num_rows() == 0) { @@ -645,7 +645,7 @@ std::unique_ptr sha_hash(table_view const& input, } std::unique_ptr sha1_hash(table_view const& input, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result("da39a3ee5e6b4b0d3255bfef95601890afd80709"); @@ -653,7 +653,7 @@ std::unique_ptr sha1_hash(table_view const& input, } std::unique_ptr sha224_hash(table_view const& input, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); @@ -661,7 +661,7 @@ std::unique_ptr sha224_hash(table_view const& input, } std::unique_ptr sha256_hash(table_view const& input, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result( @@ -670,7 +670,7 @@ std::unique_ptr sha256_hash(table_view const& input, } std::unique_ptr sha384_hash(table_view const& input, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result( @@ -680,7 +680,7 @@ std::unique_ptr sha384_hash(table_view const& input, } std::unique_ptr sha512_hash(table_view const& input, - cudaStream_t stream, + rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { string_scalar const empty_result( From c46965eebb3232e99945953d039e304ba8aeb082 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:07:43 -0700 Subject: [PATCH 037/100] Small refactorings. --- cpp/src/hash/sha_hash.cu | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index d1e2566d434..6fa0f94c7e8 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -77,8 +78,25 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) } // namespace +/** + * @brief A CRTP helper function + * + * https://www.fluentcpp.com/2017/05/19/crtp-helper/ + * + * Does two things: + * 1. Makes "crtp" explicit in the inheritance structure of a CRTP base class. + * 2. Avoids having to `static_cast` in a lot of places + * + * @tparam T The derived class in a CRTP hierarchy + */ +template +struct crtp { + __device__ T& underlying() { return static_cast(*this); } + __device__ T const& underlying() const { return static_cast(*this); } +}; + template -struct SHAHash { +struct SHAHash : public crtp { /** * @brief Execute SHA on input data chunks. * @@ -102,6 +120,7 @@ struct SHAHash { std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); Hasher::hash_step(hash_state); + // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > Hasher::message_chunk_size + copylen) { std::memcpy(hash_state->buffer, data + copylen, Hasher::message_chunk_size); Hasher::hash_step(hash_state); @@ -129,9 +148,9 @@ struct SHAHash { << 3; // Add a one bit flag to signal the end of the message - constexpr uint8_t end_of_message = 0x80; + uint8_t constexpr end_of_message = 0x80; // 1 byte for the end of the message flag - constexpr int end_of_message_size = 1; + uint32_t constexpr end_of_message_size = 1; thrust::fill_n(thrust::seq, hash_state->buffer + hash_state->buffer_length, @@ -141,7 +160,7 @@ struct SHAHash { // SHA-512 uses a 128-bit message length instead of a 64-bit message length // but this code does not support messages with lengths exceeding UINT64_MAX // bits. We always pad the upper 64 bits with zeros. - constexpr auto message_length_supported_size = sizeof(message_length_in_bits); + auto constexpr message_length_supported_size = sizeof(message_length_in_bits); if (hash_state->buffer_length + Hasher::message_length_size + end_of_message_size <= Hasher::message_chunk_size) { @@ -181,7 +200,6 @@ struct SHAHash { // include all of the hash values. auto constexpr num_words_to_copy = Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); -#pragma unroll for (int i = 0; i < num_words_to_copy; i++) { // Convert word representation from big-endian to little-endian. typename Hasher::sha_word_type flipped = swap_endian(hash_state->hash_value[i]); @@ -543,8 +561,10 @@ void __device__ sha512_hash_step(sha_intermediate_data* hash_state) } struct SHA384Hash : SHAHash { + // Intermediate data type storing the hash state using sha_intermediate_data = sha384_intermediate_data; - using sha_word_type = sha512_word_type; + // The word type used by this hash function + using sha_word_type = sha512_word_type; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 128; // Digest size in bytes. This is truncated from SHA-512. @@ -559,8 +579,10 @@ struct SHA384Hash : SHAHash { }; struct SHA512Hash : SHAHash { + // Intermediate data type storing the hash state using sha_intermediate_data = sha512_intermediate_data; - using sha_word_type = sha512_word_type; + // The word type used by this hash function + using sha_word_type = sha512_word_type; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 128; // Digest size in bytes From 540f9832a7ec50dac6830d567d3a79b7ee5cdb8e Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:34:23 -0700 Subject: [PATCH 038/100] Use process_key function. --- cpp/src/hash/sha_hash.cu | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 6fa0f94c7e8..7487713865b 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -103,12 +103,11 @@ struct SHAHash : public crtp { * This accepts arbitrary data, handles it as bytes, and calls the hash step * when the buffer is filled up to message_chunk_size bytes. */ - template - void CUDA_DEVICE_CALLABLE process(TKey const& key, + template + void CUDA_DEVICE_CALLABLE process(uint8_t const* data, + uint32_t len, typename Hasher::sha_intermediate_data* hash_state) const { - uint32_t const len = sizeof(TKey); - uint8_t const* data = reinterpret_cast(&key); hash_state->message_length += len; if (hash_state->buffer_length + len < Hasher::message_chunk_size) { @@ -132,6 +131,15 @@ struct SHAHash : public crtp { } } + template + void CUDA_DEVICE_CALLABLE process_key(TKey const& key, + typename Hasher::sha_intermediate_data* hash_state) const + { + uint8_t const* data = reinterpret_cast(&key); + uint32_t const len = sizeof(TKey); + process(data, len, hash_state); + } + /** * @brief Finalize SHA element processing. * @@ -247,11 +255,11 @@ struct SHAHash : public crtp { T const& key = col.element(row_index); if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); - process(nan, hash_state); + process_key(nan, hash_state); } else if (key == T{0.0}) { - process(T{0.0}, hash_state); + process_key(T{0.0}, hash_state); } else { - process(key, hash_state); + process_key(key, hash_state); } } @@ -263,7 +271,7 @@ struct SHAHash : public crtp { size_type row_index, typename Hasher::sha_intermediate_data* hash_state) const { - process(col.element(row_index), hash_state); + process_key(col.element(row_index), hash_state); } template Date: Mon, 20 Sep 2021 12:36:16 -0700 Subject: [PATCH 039/100] Use process function for string data. --- cpp/src/hash/sha_hash.cu | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 7487713865b..db8c5613d2e 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -282,34 +282,9 @@ struct SHAHash : public crtp { typename Hasher::sha_intermediate_data* hash_state) const { string_view key = col.element(row_index); - uint32_t const len = static_cast(key.size_bytes()); uint8_t const* data = reinterpret_cast(key.data()); - hash_state->message_length += len; - - if (hash_state->buffer_length + len < Hasher::message_chunk_size) { - // If the buffer will not be filled by this data, we copy the new data into - // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; - } else { - // The buffer will be filled by this data. Copy a chunk of the data to fill - // the buffer and trigger a hash step. - uint32_t copylen = Hasher::message_chunk_size - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); - Hasher::hash_step(hash_state); - - // Take buffer-sized chunks of the data and do a hash step on each chunk. - while (len > Hasher::message_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, Hasher::message_chunk_size); - Hasher::hash_step(hash_state); - copylen += Hasher::message_chunk_size; - } - - // The remaining data chunk does not fill the buffer. We copy the data into - // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; - } + uint32_t const len = static_cast(key.size_bytes()); + process(data, len, hash_state); } }; From 2023ac1eec6a6509d64da6ccd37864b59290da1b Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:38:18 -0700 Subject: [PATCH 040/100] Add comments to process function. --- cpp/src/hash/sha_hash.cu | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index db8c5613d2e..81a894017af 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -111,11 +111,14 @@ struct SHAHash : public crtp { hash_state->message_length += len; if (hash_state->buffer_length + len < Hasher::message_chunk_size) { + // If the buffer will not be filled by this data, we copy the new data into + // the buffer but do not trigger a hash step yet. std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); hash_state->buffer_length += len; } else { + // The buffer will be filled by this data. Copy a chunk of the data to fill + // the buffer and trigger a hash step. uint32_t copylen = Hasher::message_chunk_size - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); Hasher::hash_step(hash_state); @@ -126,6 +129,8 @@ struct SHAHash : public crtp { copylen += Hasher::message_chunk_size; } + // The remaining data chunk does not fill the buffer. We copy the data into + // the buffer but do not trigger a hash step yet. std::memcpy(hash_state->buffer, data + copylen, len - copylen); hash_state->buffer_length = len - copylen; } From 502e11a620d2733514ea2507b024fe16beab19e2 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:42:21 -0700 Subject: [PATCH 041/100] Use constexpr. --- cpp/src/hash/sha_hash.cu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 81a894017af..dd4c0d822e1 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -140,8 +140,8 @@ struct SHAHash : public crtp { void CUDA_DEVICE_CALLABLE process_key(TKey const& key, typename Hasher::sha_intermediate_data* hash_state) const { - uint8_t const* data = reinterpret_cast(&key); - uint32_t const len = sizeof(TKey); + uint8_t const* data = reinterpret_cast(&key); + uint32_t constexpr len = sizeof(TKey); process(data, len, hash_state); } From 82dd92bfe59c024d784174f8e413013c88f2422e Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:52:50 -0700 Subject: [PATCH 042/100] Split sha1_hash_step. --- cpp/src/hash/sha_hash.cu | 140 ++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index dd4c0d822e1..4e0f5843f28 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -293,6 +293,77 @@ struct SHAHash : public crtp { } }; +/** + * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, + * updating the hash value so far. Does not zero out the buffer contents. + */ +template +void __device__ sha1_hash_step(sha_intermediate_data* hash_state) +{ + uint32_t A = hash_state->hash_value[0]; + uint32_t B = hash_state->hash_value[1]; + uint32_t C = hash_state->hash_value[2]; + uint32_t D = hash_state->hash_value[3]; + uint32_t E = hash_state->hash_value[4]; + + uint32_t words[80]; + + // Word size in bytes + constexpr auto word_size = sizeof(uint32_t); + + // The 512-bit message buffer fills the first 16 words. + for (int i = 0; i < 16; i++) { + uint32_t buffer_element_as_int; + std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + // Convert word representation from little-endian to big-endian. + words[i] = swap_endian(buffer_element_as_int); + } + + // The rest of the 80 words are generated from the first 16 words. + for (int i = 16; i < 80; i++) { + uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotate_bits_left(temp, 1); + } + + for (int i = 0; i < 80; i++) { + uint32_t F; + uint32_t temp; + uint32_t k; + switch (i / 20) { + case 0: + F = D ^ (B & (C ^ D)); + k = 0x5a827999; + break; + case 1: + F = B ^ C ^ D; + k = 0x6ed9eba1; + break; + case 2: + F = (B & C) | (B & D) | (C & D); + k = 0x8f1bbcdc; + break; + case 3: + F = B ^ C ^ D; + k = 0xca62c1d6; + break; + } + temp = rotate_bits_left(A, 5) + F + E + k + words[i]; + E = D; + D = C; + C = rotate_bits_left(B, 30); + B = A; + A = temp; + } + + hash_state->hash_value[0] += A; + hash_state->hash_value[1] += B; + hash_state->hash_value[2] += C; + hash_state->hash_value[3] += D; + hash_state->hash_value[4] += E; + + hash_state->buffer_length = 0; +} + struct SHA1Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha1_intermediate_data; @@ -305,74 +376,9 @@ struct SHA1Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - /** - * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, - * updating the hash value so far. Does not zero out the buffer contents. - */ - static void __device__ hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - uint32_t E = hash_state->hash_value[4]; - - uint32_t words[80]; - - // Word size in bytes - constexpr auto word_size = sizeof(uint32_t); - - // The 512-bit message buffer fills the first 16 words. - for (int i = 0; i < 16; i++) { - uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); - // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); - } - - // The rest of the 80 words are generated from the first 16 words. - for (int i = 16; i < 80; i++) { - uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = rotate_bits_left(temp, 1); - } - - for (int i = 0; i < 80; i++) { - uint32_t F; - uint32_t temp; - uint32_t k; - switch (i / 20) { - case 0: - F = D ^ (B & (C ^ D)); - k = 0x5a827999; - break; - case 1: - F = B ^ C ^ D; - k = 0x6ed9eba1; - break; - case 2: - F = (B & C) | (B & D) | (C & D); - k = 0x8f1bbcdc; - break; - case 3: - F = B ^ C ^ D; - k = 0xca62c1d6; - break; - } - temp = rotate_bits_left(A, 5) + F + E + k + words[i]; - E = D; - D = C; - C = rotate_bits_left(B, 30); - B = A; - A = temp; - } - - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; - - hash_state->buffer_length = 0; + sha1_hash_step(hash_state); } }; From f05a43a93095b94baaf5ff7e620385fec59ed052 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 12:54:07 -0700 Subject: [PATCH 043/100] Move hash step functions above the SHA classes. --- cpp/src/hash/sha_hash.cu | 100 +++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 4e0f5843f28..6313e8abad4 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -364,24 +364,6 @@ void __device__ sha1_hash_step(sha_intermediate_data* hash_state) hash_state->buffer_length = 0; } -struct SHA1Hash : SHAHash { - // Intermediate data type storing the hash state - using sha_intermediate_data = sha1_intermediate_data; - // The word type used by this hash function - using sha_word_type = sha1_word_type; - // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; - // Digest size in bytes - static constexpr auto digest_size = 40; - // Number of bytes used for the message length - static constexpr auto message_length_size = 8; - - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) - { - sha1_hash_step(hash_state); - } -}; - /** * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -452,38 +434,6 @@ void __device__ sha256_hash_step(sha_intermediate_data* hash_state) hash_state->buffer_length = 0; } -struct SHA224Hash : SHAHash { - using sha_intermediate_data = sha224_intermediate_data; - using sha_word_type = sha256_word_type; - // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; - // Digest size in bytes. This is truncated from SHA-256. - static constexpr auto digest_size = 56; - // Number of bytes used for the message length - static constexpr auto message_length_size = 8; - - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) - { - sha256_hash_step(hash_state); - } -}; - -struct SHA256Hash : SHAHash { - using sha_intermediate_data = sha256_intermediate_data; - using sha_word_type = sha256_word_type; - // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; - // Digest size in bytes - static constexpr auto digest_size = 64; - // Number of bytes used for the message length - static constexpr auto message_length_size = 8; - - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) - { - sha256_hash_step(hash_state); - } -}; - /** * @brief Core SHA-512 algorithm implementation. Processes a single 1024-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -554,6 +504,56 @@ void __device__ sha512_hash_step(sha_intermediate_data* hash_state) hash_state->buffer_length = 0; } +struct SHA1Hash : SHAHash { + // Intermediate data type storing the hash state + using sha_intermediate_data = sha1_intermediate_data; + // The word type used by this hash function + using sha_word_type = sha1_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes + static constexpr auto digest_size = 40; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; + + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + { + sha1_hash_step(hash_state); + } +}; + +struct SHA224Hash : SHAHash { + using sha_intermediate_data = sha224_intermediate_data; + using sha_word_type = sha256_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes. This is truncated from SHA-256. + static constexpr auto digest_size = 56; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; + + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + { + sha256_hash_step(hash_state); + } +}; + +struct SHA256Hash : SHAHash { + using sha_intermediate_data = sha256_intermediate_data; + using sha_word_type = sha256_word_type; + // Number of bytes processed in each hash step + static constexpr auto message_chunk_size = 64; + // Digest size in bytes + static constexpr auto digest_size = 64; + // Number of bytes used for the message length + static constexpr auto message_length_size = 8; + + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + { + sha256_hash_step(hash_state); + } +}; + struct SHA384Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha384_intermediate_data; From f291c93000e4d9fa596cdd82f6ff980009f6de47 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 13:23:37 -0700 Subject: [PATCH 044/100] Use east const, add comments. --- cpp/src/hash/sha_hash.cu | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 6313e8abad4..b91e36820b2 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -309,7 +309,7 @@ void __device__ sha1_hash_step(sha_intermediate_data* hash_state) uint32_t words[80]; // Word size in bytes - constexpr auto word_size = sizeof(uint32_t); + auto constexpr word_size = sizeof(uint32_t); // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { @@ -383,7 +383,7 @@ void __device__ sha256_hash_step(sha_intermediate_data* hash_state) uint32_t words[64]; // Word size in bytes - constexpr auto word_size = sizeof(uint32_t); + auto constexpr word_size = sizeof(uint32_t); // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { @@ -453,7 +453,7 @@ void __device__ sha512_hash_step(sha_intermediate_data* hash_state) uint64_t words[80]; // Word size in bytes - constexpr auto word_size = sizeof(uint64_t); + auto constexpr word_size = sizeof(uint64_t); // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { @@ -523,8 +523,10 @@ struct SHA1Hash : SHAHash { }; struct SHA224Hash : SHAHash { + // Intermediate data type storing the hash state using sha_intermediate_data = sha224_intermediate_data; - using sha_word_type = sha256_word_type; + // The word type used by this hash function + using sha_word_type = sha256_word_type; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 64; // Digest size in bytes. This is truncated from SHA-256. @@ -539,8 +541,10 @@ struct SHA224Hash : SHAHash { }; struct SHA256Hash : SHAHash { + // Intermediate data type storing the hash state using sha_intermediate_data = sha256_intermediate_data; - using sha_word_type = sha256_word_type; + // The word type used by this hash function + using sha_word_type = sha256_word_type; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 64; // Digest size in bytes From 4b49f2f4ecfb32ccba8a3e07709e4d5c46187dda Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 13:46:56 -0700 Subject: [PATCH 045/100] Pass hash state by reference. --- cpp/src/hash/sha_hash.cu | 115 ++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index b91e36820b2..2fc2a0e10ab 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -298,13 +298,13 @@ struct SHAHash : public crtp { * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha1_hash_step(sha_intermediate_data* hash_state) +void __device__ sha1_hash_step(sha_intermediate_data& hash_state) { - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - uint32_t E = hash_state->hash_value[4]; + uint32_t A = hash_state.hash_value[0]; + uint32_t B = hash_state.hash_value[1]; + uint32_t C = hash_state.hash_value[2]; + uint32_t D = hash_state.hash_value[3]; + uint32_t E = hash_state.hash_value[4]; uint32_t words[80]; @@ -314,7 +314,7 @@ void __device__ sha1_hash_step(sha_intermediate_data* hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } @@ -355,13 +355,13 @@ void __device__ sha1_hash_step(sha_intermediate_data* hash_state) A = temp; } - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; + hash_state.hash_value[0] += A; + hash_state.hash_value[1] += B; + hash_state.hash_value[2] += C; + hash_state.hash_value[3] += D; + hash_state.hash_value[4] += E; - hash_state->buffer_length = 0; + hash_state.buffer_length = 0; } /** @@ -369,16 +369,16 @@ void __device__ sha1_hash_step(sha_intermediate_data* hash_state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha256_hash_step(sha_intermediate_data* hash_state) +void __device__ sha256_hash_step(sha_intermediate_data& hash_state) { - uint32_t A = hash_state->hash_value[0]; - uint32_t B = hash_state->hash_value[1]; - uint32_t C = hash_state->hash_value[2]; - uint32_t D = hash_state->hash_value[3]; - uint32_t E = hash_state->hash_value[4]; - uint32_t F = hash_state->hash_value[5]; - uint32_t G = hash_state->hash_value[6]; - uint32_t H = hash_state->hash_value[7]; + uint32_t A = hash_state.hash_value[0]; + uint32_t B = hash_state.hash_value[1]; + uint32_t C = hash_state.hash_value[2]; + uint32_t D = hash_state.hash_value[3]; + uint32_t E = hash_state.hash_value[4]; + uint32_t F = hash_state.hash_value[5]; + uint32_t G = hash_state.hash_value[6]; + uint32_t H = hash_state.hash_value[7]; uint32_t words[64]; @@ -388,7 +388,7 @@ void __device__ sha256_hash_step(sha_intermediate_data* hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } @@ -422,16 +422,16 @@ void __device__ sha256_hash_step(sha_intermediate_data* hash_state) A = temp1 + temp2; } - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; - hash_state->hash_value[5] += F; - hash_state->hash_value[6] += G; - hash_state->hash_value[7] += H; + hash_state.hash_value[0] += A; + hash_state.hash_value[1] += B; + hash_state.hash_value[2] += C; + hash_state.hash_value[3] += D; + hash_state.hash_value[4] += E; + hash_state.hash_value[5] += F; + hash_state.hash_value[6] += G; + hash_state.hash_value[7] += H; - hash_state->buffer_length = 0; + hash_state.buffer_length = 0; } /** @@ -439,16 +439,16 @@ void __device__ sha256_hash_step(sha_intermediate_data* hash_state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha512_hash_step(sha_intermediate_data* hash_state) +void __device__ sha512_hash_step(sha_intermediate_data& hash_state) { - uint64_t A = hash_state->hash_value[0]; - uint64_t B = hash_state->hash_value[1]; - uint64_t C = hash_state->hash_value[2]; - uint64_t D = hash_state->hash_value[3]; - uint64_t E = hash_state->hash_value[4]; - uint64_t F = hash_state->hash_value[5]; - uint64_t G = hash_state->hash_value[6]; - uint64_t H = hash_state->hash_value[7]; + uint64_t A = hash_state.hash_value[0]; + uint64_t B = hash_state.hash_value[1]; + uint64_t C = hash_state.hash_value[2]; + uint64_t D = hash_state.hash_value[3]; + uint64_t E = hash_state.hash_value[4]; + uint64_t F = hash_state.hash_value[5]; + uint64_t G = hash_state.hash_value[6]; + uint64_t H = hash_state.hash_value[7]; uint64_t words[80]; @@ -458,7 +458,7 @@ void __device__ sha512_hash_step(sha_intermediate_data* hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint64_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state->buffer + (i * word_size), word_size); + std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } @@ -492,16 +492,16 @@ void __device__ sha512_hash_step(sha_intermediate_data* hash_state) A = temp1 + temp2; } - hash_state->hash_value[0] += A; - hash_state->hash_value[1] += B; - hash_state->hash_value[2] += C; - hash_state->hash_value[3] += D; - hash_state->hash_value[4] += E; - hash_state->hash_value[5] += F; - hash_state->hash_value[6] += G; - hash_state->hash_value[7] += H; + hash_state.hash_value[0] += A; + hash_state.hash_value[1] += B; + hash_state.hash_value[2] += C; + hash_state.hash_value[3] += D; + hash_state.hash_value[4] += E; + hash_state.hash_value[5] += F; + hash_state.hash_value[6] += G; + hash_state.hash_value[7] += H; - hash_state->buffer_length = 0; + hash_state.buffer_length = 0; } struct SHA1Hash : SHAHash { @@ -518,7 +518,7 @@ struct SHA1Hash : SHAHash { static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha1_hash_step(hash_state); + sha1_hash_step(*hash_state); } }; @@ -536,7 +536,7 @@ struct SHA224Hash : SHAHash { static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha256_hash_step(hash_state); + sha256_hash_step(*hash_state); } }; @@ -554,7 +554,7 @@ struct SHA256Hash : SHAHash { static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha256_hash_step(hash_state); + sha256_hash_step(*hash_state); } }; @@ -572,7 +572,7 @@ struct SHA384Hash : SHAHash { static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha512_hash_step(hash_state); + sha512_hash_step(*hash_state); } }; @@ -590,7 +590,7 @@ struct SHA512Hash : SHAHash { static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) { - sha512_hash_step(hash_state); + sha512_hash_step(*hash_state); } }; @@ -657,7 +657,8 @@ std::unique_ptr sha_hash(table_view const& input, &hash_state); } } - hasher.finalize(&hash_state, d_chars + (row_index * Hasher::digest_size)); + auto const result_location = d_chars + (row_index * Hasher::digest_size); + hasher.finalize(&hash_state, result_location); }); return make_strings_column( From 0ffa903c23b76dc5b6a0cf7d7409792ccf59ea5c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 13:51:24 -0700 Subject: [PATCH 046/100] Pass hash state by reference in operator and process functions. --- cpp/src/hash/sha_hash.cu | 79 ++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 2fc2a0e10ab..dc0bb3db9a2 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -106,39 +106,39 @@ struct SHAHash : public crtp { template void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { - hash_state->message_length += len; + hash_state.message_length += len; - if (hash_state->buffer_length + len < Hasher::message_chunk_size) { + if (hash_state.buffer_length + len < Hasher::message_chunk_size) { // If the buffer will not be filled by this data, we copy the new data into // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, len); - hash_state->buffer_length += len; + std::memcpy(hash_state.buffer + hash_state.buffer_length, data, len); + hash_state.buffer_length += len; } else { // The buffer will be filled by this data. Copy a chunk of the data to fill // the buffer and trigger a hash step. - uint32_t copylen = Hasher::message_chunk_size - hash_state->buffer_length; - std::memcpy(hash_state->buffer + hash_state->buffer_length, data, copylen); + uint32_t copylen = Hasher::message_chunk_size - hash_state.buffer_length; + std::memcpy(hash_state.buffer + hash_state.buffer_length, data, copylen); Hasher::hash_step(hash_state); // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > Hasher::message_chunk_size + copylen) { - std::memcpy(hash_state->buffer, data + copylen, Hasher::message_chunk_size); + std::memcpy(hash_state.buffer, data + copylen, Hasher::message_chunk_size); Hasher::hash_step(hash_state); copylen += Hasher::message_chunk_size; } // The remaining data chunk does not fill the buffer. We copy the data into // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state->buffer, data + copylen, len - copylen); - hash_state->buffer_length = len - copylen; + std::memcpy(hash_state.buffer, data + copylen, len - copylen); + hash_state.buffer_length = len - copylen; } } template void CUDA_DEVICE_CALLABLE process_key(TKey const& key, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { uint8_t const* data = reinterpret_cast(&key); uint32_t constexpr len = sizeof(TKey); @@ -153,12 +153,11 @@ struct SHAHash : public crtp { * the final hash step. */ template - void CUDA_DEVICE_CALLABLE finalize(typename Hasher::sha_intermediate_data* hash_state, + void CUDA_DEVICE_CALLABLE finalize(typename Hasher::sha_intermediate_data& hash_state, char* result_location) { // Message length in bits. - uint64_t const message_length_in_bits = (static_cast(hash_state->message_length)) - << 3; + uint64_t const message_length_in_bits = (static_cast(hash_state.message_length)) << 3; // Add a one bit flag to signal the end of the message uint8_t constexpr end_of_message = 0x80; @@ -166,7 +165,7 @@ struct SHAHash : public crtp { uint32_t constexpr end_of_message_size = 1; thrust::fill_n(thrust::seq, - hash_state->buffer + hash_state->buffer_length, + hash_state.buffer + hash_state.buffer_length, end_of_message_size, end_of_message); @@ -175,35 +174,35 @@ struct SHAHash : public crtp { // bits. We always pad the upper 64 bits with zeros. auto constexpr message_length_supported_size = sizeof(message_length_in_bits); - if (hash_state->buffer_length + Hasher::message_length_size + end_of_message_size <= + if (hash_state.buffer_length + Hasher::message_length_size + end_of_message_size <= Hasher::message_chunk_size) { // Fill the remainder of the buffer with zeros up to the space reserved // for the message length. The message length fits in this hash step. thrust::fill(thrust::seq, - hash_state->buffer + hash_state->buffer_length + end_of_message_size, - hash_state->buffer + Hasher::message_chunk_size - message_length_supported_size, + hash_state.buffer + hash_state.buffer_length + end_of_message_size, + hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, 0x00); } else { // Fill the remainder of the buffer with zeros. The message length doesn't // fit and will be processed in a subsequent hash step comprised of only // zeros followed by the message length. thrust::fill(thrust::seq, - hash_state->buffer + hash_state->buffer_length + end_of_message_size, - hash_state->buffer + Hasher::message_chunk_size, + hash_state.buffer + hash_state.buffer_length + end_of_message_size, + hash_state.buffer + Hasher::message_chunk_size, 0x00); Hasher::hash_step(hash_state); // Fill the entire message with zeros up to the final bytes reserved for // the message length. thrust::fill_n(thrust::seq, - hash_state->buffer, + hash_state.buffer, Hasher::message_chunk_size - message_length_supported_size, 0x00); } // Convert the 64-bit message length from little-endian to big-endian. uint64_t const full_length_flipped = swap_endian(message_length_in_bits); - std::memcpy(hash_state->buffer + Hasher::message_chunk_size - message_length_supported_size, + std::memcpy(hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), message_length_supported_size); Hasher::hash_step(hash_state); @@ -215,7 +214,7 @@ struct SHAHash : public crtp { Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); for (int i = 0; i < num_words_to_copy; i++) { // Convert word representation from big-endian to little-endian. - typename Hasher::sha_word_type flipped = swap_endian(hash_state->hash_value[i]); + typename Hasher::sha_word_type flipped = swap_endian(hash_state.hash_value[i]); if constexpr (std::is_same_v) { uint32ToLowercaseHexString(flipped, result_location + (8 * i)); } else if constexpr (std::is_same_v) { @@ -234,7 +233,7 @@ struct SHAHash : public crtp { typename std::enable_if_t()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { cudf_assert(false && "SHA Unsupported chrono type column"); } @@ -245,7 +244,7 @@ struct SHAHash : public crtp { typename std::enable_if_t() && !std::is_same_v>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { cudf_assert(false && "SHA Unsupported non-fixed-width type column"); } @@ -255,7 +254,7 @@ struct SHAHash : public crtp { typename std::enable_if_t()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { T const& key = col.element(row_index); if (isnan(key)) { @@ -274,7 +273,7 @@ struct SHAHash : public crtp { !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { process_key(col.element(row_index), hash_state); } @@ -284,7 +283,7 @@ struct SHAHash : public crtp { typename std::enable_if_t>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data* hash_state) const + typename Hasher::sha_intermediate_data& hash_state) const { string_view key = col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); @@ -516,9 +515,9 @@ struct SHA1Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { - sha1_hash_step(*hash_state); + sha1_hash_step(hash_state); } }; @@ -534,9 +533,9 @@ struct SHA224Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { - sha256_hash_step(*hash_state); + sha256_hash_step(hash_state); } }; @@ -552,9 +551,9 @@ struct SHA256Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { - sha256_hash_step(*hash_state); + sha256_hash_step(hash_state); } }; @@ -570,9 +569,9 @@ struct SHA384Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 16; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { - sha512_hash_step(*hash_state); + sha512_hash_step(hash_state); } }; @@ -588,9 +587,9 @@ struct SHA512Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 16; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data* hash_state) + static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { - sha512_hash_step(*hash_state); + sha512_hash_step(hash_state); } }; @@ -654,11 +653,11 @@ std::unique_ptr sha_hash(table_view const& input, hasher, device_input.column(col_index), row_index, - &hash_state); + hash_state); } } auto const result_location = d_chars + (row_index * Hasher::digest_size); - hasher.finalize(&hash_state, result_location); + hasher.finalize(hash_state, result_location); }); return make_strings_column( From 84c034df858a12cb7980eb9e66c5c187aa7034e3 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 13:53:10 -0700 Subject: [PATCH 047/100] Update comment. --- cpp/src/hash/sha_hash.cu | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index dc0bb3db9a2..2b075fc1344 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -111,7 +111,7 @@ struct SHAHash : public crtp { hash_state.message_length += len; if (hash_state.buffer_length + len < Hasher::message_chunk_size) { - // If the buffer will not be filled by this data, we copy the new data into + // The buffer will not be filled by this data. We copy the new data into // the buffer but do not trigger a hash step yet. std::memcpy(hash_state.buffer + hash_state.buffer_length, data, len); hash_state.buffer_length += len; @@ -158,7 +158,6 @@ struct SHAHash : public crtp { { // Message length in bits. uint64_t const message_length_in_bits = (static_cast(hash_state.message_length)) << 3; - // Add a one bit flag to signal the end of the message uint8_t constexpr end_of_message = 0x80; // 1 byte for the end of the message flag From 987992ec0a4ac9d90b10e94e0ccc1ee8dfbf75c3 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 20 Sep 2021 17:06:50 -0700 Subject: [PATCH 048/100] Store sha_intermediate_data in Hasher instance. --- cpp/src/hash/sha_hash.cu | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 2b075fc1344..36309f94bbf 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -91,8 +91,8 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) */ template struct crtp { - __device__ T& underlying() { return static_cast(*this); } - __device__ T const& underlying() const { return static_cast(*this); } + CUDA_DEVICE_CALLABLE T& underlying() { return static_cast(*this); } + CUDA_DEVICE_CALLABLE T const& underlying() const { return static_cast(*this); } }; template @@ -296,7 +296,7 @@ struct SHAHash : public crtp { * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha1_hash_step(sha_intermediate_data& hash_state) +void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) { uint32_t A = hash_state.hash_value[0]; uint32_t B = hash_state.hash_value[1]; @@ -367,7 +367,7 @@ void __device__ sha1_hash_step(sha_intermediate_data& hash_state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha256_hash_step(sha_intermediate_data& hash_state) +void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) { uint32_t A = hash_state.hash_value[0]; uint32_t B = hash_state.hash_value[1]; @@ -437,7 +437,7 @@ void __device__ sha256_hash_step(sha_intermediate_data& hash_state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void __device__ sha512_hash_step(sha_intermediate_data& hash_state) +void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) { uint64_t A = hash_state.hash_value[0]; uint64_t B = hash_state.hash_value[1]; @@ -518,6 +518,8 @@ struct SHA1Hash : SHAHash { { sha1_hash_step(hash_state); } + + sha_intermediate_data hash_state; }; struct SHA224Hash : SHAHash { @@ -536,6 +538,8 @@ struct SHA224Hash : SHAHash { { sha256_hash_step(hash_state); } + + sha_intermediate_data hash_state; }; struct SHA256Hash : SHAHash { @@ -554,6 +558,8 @@ struct SHA256Hash : SHAHash { { sha256_hash_step(hash_state); } + + sha_intermediate_data hash_state; }; struct SHA384Hash : SHAHash { @@ -572,6 +578,8 @@ struct SHA384Hash : SHAHash { { sha512_hash_step(hash_state); } + + sha_intermediate_data hash_state; }; struct SHA512Hash : SHAHash { @@ -590,6 +598,8 @@ struct SHA512Hash : SHAHash { { sha512_hash_step(hash_state); } + + sha_intermediate_data hash_state; }; /** @@ -643,7 +653,6 @@ std::unique_ptr sha_hash(table_view const& input, thrust::make_counting_iterator(0), thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { - typename Hasher::sha_intermediate_data hash_state; Hasher hasher = Hasher{}; for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { @@ -652,11 +661,11 @@ std::unique_ptr sha_hash(table_view const& input, hasher, device_input.column(col_index), row_index, - hash_state); + hasher.hash_state); } } auto const result_location = d_chars + (row_index * Hasher::digest_size); - hasher.finalize(hash_state, result_location); + hasher.finalize(hasher.hash_state, result_location); }); return make_strings_column( From 8e38d61d0226f7c633a3b6d6e0160956fb509130 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 07:38:55 -0700 Subject: [PATCH 049/100] Drop const. --- cpp/src/hash/sha_hash.cu | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 36309f94bbf..1cb82c69c71 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -106,7 +106,7 @@ struct SHAHash : public crtp { template void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { hash_state.message_length += len; @@ -138,7 +138,7 @@ struct SHAHash : public crtp { template void CUDA_DEVICE_CALLABLE process_key(TKey const& key, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { uint8_t const* data = reinterpret_cast(&key); uint32_t constexpr len = sizeof(TKey); @@ -232,7 +232,7 @@ struct SHAHash : public crtp { typename std::enable_if_t()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { cudf_assert(false && "SHA Unsupported chrono type column"); } @@ -243,7 +243,7 @@ struct SHAHash : public crtp { typename std::enable_if_t() && !std::is_same_v>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { cudf_assert(false && "SHA Unsupported non-fixed-width type column"); } @@ -253,7 +253,7 @@ struct SHAHash : public crtp { typename std::enable_if_t()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { T const& key = col.element(row_index); if (isnan(key)) { @@ -272,7 +272,7 @@ struct SHAHash : public crtp { !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { process_key(col.element(row_index), hash_state); } @@ -282,7 +282,7 @@ struct SHAHash : public crtp { typename std::enable_if_t>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) const + typename Hasher::sha_intermediate_data& hash_state) { string_view key = col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); From 56ab37bb4f9fe887d374990f3e6f13a4235070a8 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 07:39:15 -0700 Subject: [PATCH 050/100] Use underlying for hash_step calls. --- cpp/src/hash/sha_hash.cu | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 1cb82c69c71..ecb6dccca55 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -120,12 +120,12 @@ struct SHAHash : public crtp { // the buffer and trigger a hash step. uint32_t copylen = Hasher::message_chunk_size - hash_state.buffer_length; std::memcpy(hash_state.buffer + hash_state.buffer_length, data, copylen); - Hasher::hash_step(hash_state); + this->underlying().hash_step(hash_state); // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > Hasher::message_chunk_size + copylen) { std::memcpy(hash_state.buffer, data + copylen, Hasher::message_chunk_size); - Hasher::hash_step(hash_state); + this->underlying().hash_step(hash_state); copylen += Hasher::message_chunk_size; } @@ -189,7 +189,7 @@ struct SHAHash : public crtp { hash_state.buffer + hash_state.buffer_length + end_of_message_size, hash_state.buffer + Hasher::message_chunk_size, 0x00); - Hasher::hash_step(hash_state); + this->underlying().hash_step(hash_state); // Fill the entire message with zeros up to the final bytes reserved for // the message length. @@ -204,7 +204,7 @@ struct SHAHash : public crtp { std::memcpy(hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), message_length_supported_size); - Hasher::hash_step(hash_state); + this->underlying().hash_step(hash_state); // Each byte in the word generates two bytes in the hexadecimal string digest. // SHA-224 and SHA-384 digests are truncated because their digest does not @@ -514,7 +514,7 @@ struct SHA1Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { sha1_hash_step(hash_state); } @@ -534,7 +534,7 @@ struct SHA224Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { sha256_hash_step(hash_state); } @@ -554,7 +554,7 @@ struct SHA256Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 8; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { sha256_hash_step(hash_state); } @@ -574,7 +574,7 @@ struct SHA384Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 16; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { sha512_hash_step(hash_state); } @@ -594,7 +594,7 @@ struct SHA512Hash : SHAHash { // Number of bytes used for the message length static constexpr auto message_length_size = 16; - static void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { sha512_hash_step(hash_state); } From b9a37cd6617a993623364b4b7b74b162a952230c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 09:41:05 -0700 Subject: [PATCH 051/100] Use memcpy instead of std::memcpy. --- cpp/src/hash/sha_hash.cu | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index ecb6dccca55..8d9d9cc5fcc 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -113,25 +113,25 @@ struct SHAHash : public crtp { if (hash_state.buffer_length + len < Hasher::message_chunk_size) { // The buffer will not be filled by this data. We copy the new data into // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state.buffer + hash_state.buffer_length, data, len); + memcpy(hash_state.buffer + hash_state.buffer_length, data, len); hash_state.buffer_length += len; } else { // The buffer will be filled by this data. Copy a chunk of the data to fill // the buffer and trigger a hash step. uint32_t copylen = Hasher::message_chunk_size - hash_state.buffer_length; - std::memcpy(hash_state.buffer + hash_state.buffer_length, data, copylen); + memcpy(hash_state.buffer + hash_state.buffer_length, data, copylen); this->underlying().hash_step(hash_state); // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > Hasher::message_chunk_size + copylen) { - std::memcpy(hash_state.buffer, data + copylen, Hasher::message_chunk_size); + memcpy(hash_state.buffer, data + copylen, Hasher::message_chunk_size); this->underlying().hash_step(hash_state); copylen += Hasher::message_chunk_size; } // The remaining data chunk does not fill the buffer. We copy the data into // the buffer but do not trigger a hash step yet. - std::memcpy(hash_state.buffer, data + copylen, len - copylen); + memcpy(hash_state.buffer, data + copylen, len - copylen); hash_state.buffer_length = len - copylen; } } @@ -201,9 +201,9 @@ struct SHAHash : public crtp { // Convert the 64-bit message length from little-endian to big-endian. uint64_t const full_length_flipped = swap_endian(message_length_in_bits); - std::memcpy(hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, - reinterpret_cast(&full_length_flipped), - message_length_supported_size); + memcpy(hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, + reinterpret_cast(&full_length_flipped), + message_length_supported_size); this->underlying().hash_step(hash_state); // Each byte in the word generates two bytes in the hexadecimal string digest. @@ -312,7 +312,7 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); + memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } @@ -386,7 +386,7 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint32_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); + memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } @@ -456,7 +456,7 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) // The 512-bit message buffer fills the first 16 words. for (int i = 0; i < 16; i++) { uint64_t buffer_element_as_int; - std::memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); + memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. words[i] = swap_endian(buffer_element_as_int); } From 5ae53caa8b721e6047a7df91083d10438a3aaaa9 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 09:41:55 -0700 Subject: [PATCH 052/100] Update Java enum. --- java/src/main/java/ai/rapids/cudf/HashType.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java/src/main/java/ai/rapids/cudf/HashType.java b/java/src/main/java/ai/rapids/cudf/HashType.java index eb31edd8222..eaa6218b127 100644 --- a/java/src/main/java/ai/rapids/cudf/HashType.java +++ b/java/src/main/java/ai/rapids/cudf/HashType.java @@ -26,7 +26,12 @@ public enum HashType { MURMUR3(1), HASH_MD5(2), HASH_SERIAL_MURMUR3(3), - HASH_SPARK_MURMUR3(4); + HASH_SPARK_MURMUR3(4), + HASH_SHA1(5), + HASH_SHA224(6), + HASH_SHA256(7), + HASH_SHA384(8), + HASH_SHA512(9); private static final HashType[] HASH_TYPES = HashType.values(); final int nativeId; @@ -34,7 +39,7 @@ public enum HashType { HashType(int nativeId) { this.nativeId = nativeId; } - + public int getNativeId() { return nativeId; } From 1591793e849c9e445b996f28698ba4afcfd7f875 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 09:42:14 -0700 Subject: [PATCH 053/100] Update Cython enum. --- python/cudf/cudf/_lib/cpp/types.pxd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/cudf/cudf/_lib/cpp/types.pxd b/python/cudf/cudf/_lib/cpp/types.pxd index 1f2094b3958..fdbf9129e3c 100644 --- a/python/cudf/cudf/_lib/cpp/types.pxd +++ b/python/cudf/cudf/_lib/cpp/types.pxd @@ -86,6 +86,11 @@ cdef extern from "cudf/types.hpp" namespace "cudf" nogil: HASH_MD5 "cudf::hash_id::HASH_MD5" HASH_SERIAL_MURMUR3 "cudf::hash_id::HASH_SERIAL_MURMUR3" HASH_SPARK_MURMUR3 "cudf::hash_id::HASH_SPARK_MURMUR3" + HASH_SHA1 "cudf::hash_id::HASH_SHA1" + HASH_SHA224 "cudf::hash_id::HASH_SHA224" + HASH_SHA256 "cudf::hash_id::HASH_SHA256" + HASH_SHA384 "cudf::hash_id::HASH_SHA384" + HASH_SHA512 "cudf::hash_id::HASH_SHA512" cdef cppclass data_type: data_type() except + From dbd469cf62585945ae79c2ed9bab53b48664ed67 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 09:59:53 -0700 Subject: [PATCH 054/100] Rename fixed width process function. --- cpp/src/hash/sha_hash.cu | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 8d9d9cc5fcc..5cf1d44e786 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -136,12 +136,12 @@ struct SHAHash : public crtp { } } - template - void CUDA_DEVICE_CALLABLE process_key(TKey const& key, - typename Hasher::sha_intermediate_data& hash_state) + template + void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key, + typename Hasher::sha_intermediate_data& hash_state) { uint8_t const* data = reinterpret_cast(&key); - uint32_t constexpr len = sizeof(TKey); + uint32_t constexpr len = sizeof(T); process(data, len, hash_state); } @@ -258,11 +258,11 @@ struct SHAHash : public crtp { T const& key = col.element(row_index); if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); - process_key(nan, hash_state); + process_fixed_width(nan, hash_state); } else if (key == T{0.0}) { - process_key(T{0.0}, hash_state); + process_fixed_width(T{0.0}, hash_state); } else { - process_key(key, hash_state); + process_fixed_width(key, hash_state); } } @@ -274,7 +274,7 @@ struct SHAHash : public crtp { size_type row_index, typename Hasher::sha_intermediate_data& hash_state) { - process_key(col.element(row_index), hash_state); + process_fixed_width(col.element(row_index), hash_state); } template Date: Tue, 21 Sep 2021 11:00:05 -0700 Subject: [PATCH 055/100] Combine unsupported type dispatches. --- cpp/src/hash/sha_hash.cu | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 5cf1d44e786..12d47f9a0a7 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -228,24 +228,14 @@ struct SHAHash : public crtp { }; template ()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) - { - cudf_assert(false && "SHA Unsupported chrono type column"); - } - - template < - typename T, - typename Hasher = HasherT, - typename std::enable_if_t() && !std::is_same_v>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) + typename Hasher = HasherT, + typename std::enable_if_t<(!is_fixed_width() || is_chrono()) && + !std::is_same_v>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(column_device_view, + size_type, + typename Hasher::sha_intermediate_data&) { - cudf_assert(false && "SHA Unsupported non-fixed-width type column"); + cudf_assert(false && "SHA unsupported type."); } template Date: Tue, 21 Sep 2021 11:00:23 -0700 Subject: [PATCH 056/100] Use const&. --- cpp/src/hash/sha_hash.cu | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 12d47f9a0a7..53255585c27 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -621,7 +621,8 @@ std::unique_ptr sha_hash(table_view const& input, // Accepts string and fixed width columns. // TODO: Accept single layer list columns holding those types. CUDF_EXPECTS( - std::all_of(input.begin(), input.end(), [](auto col) { return sha_type_check(col.type()); }), + std::all_of( + input.begin(), input.end(), [](auto const& col) { return sha_type_check(col.type()); }), "SHA unsupported column type"); // Result column allocation and creation From 952251b249b4d57c13315be2725879428b8f95a1 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 11:18:15 -0700 Subject: [PATCH 057/100] Perform memcpys once instead of as a loop. --- cpp/src/hash/sha_hash.cu | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 53255585c27..f9d45ba6aba 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -300,11 +300,10 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) auto constexpr word_size = sizeof(uint32_t); // The 512-bit message buffer fills the first 16 words. + memcpy(&words[0], hash_state.buffer, word_size * 16); for (int i = 0; i < 16; i++) { - uint32_t buffer_element_as_int; - memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); + words[i] = swap_endian(words[i]); } // The rest of the 80 words are generated from the first 16 words. @@ -374,11 +373,10 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) auto constexpr word_size = sizeof(uint32_t); // The 512-bit message buffer fills the first 16 words. + memcpy(&words[0], hash_state.buffer, word_size * 16); for (int i = 0; i < 16; i++) { - uint32_t buffer_element_as_int; - memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); + words[i] = swap_endian(words[i]); } // The rest of the 64 words are generated from the first 16 words. @@ -443,12 +441,11 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) // Word size in bytes auto constexpr word_size = sizeof(uint64_t); - // The 512-bit message buffer fills the first 16 words. + // The 1024-bit message buffer fills the first 16 words. + memcpy(&words[0], hash_state.buffer, word_size * 16); for (int i = 0; i < 16; i++) { - uint64_t buffer_element_as_int; - memcpy(&buffer_element_as_int, hash_state.buffer + (i * word_size), word_size); // Convert word representation from little-endian to big-endian. - words[i] = swap_endian(buffer_element_as_int); + words[i] = swap_endian(words[i]); } // The rest of the 80 words are generated from the first 16 words. From 2474ec9e69b0acbf46efc7569d58d2b88dc109d3 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 13:00:14 -0700 Subject: [PATCH 058/100] Move hash constants into sha_hash.cu. --- cpp/src/hash/hash_constants.hpp | 91 ------------------------------- cpp/src/hash/sha_hash.cu | 94 +++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 96 deletions(-) diff --git a/cpp/src/hash/hash_constants.hpp b/cpp/src/hash/hash_constants.hpp index ff0486f3b51..0a5a9e0be93 100644 --- a/cpp/src/hash/hash_constants.hpp +++ b/cpp/src/hash/hash_constants.hpp @@ -60,96 +60,5 @@ __device__ __constant__ md5_hash_constants_type md5_hash_constants[64] = { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; - -using sha1_word_type = uint32_t; - -struct sha1_intermediate_data { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; - uint8_t buffer[64]; -}; - -using sha256_word_type = uint32_t; - -struct sha256_intermediate_data { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - uint8_t buffer[64]; -}; - -struct sha224_intermediate_data { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[8] = { - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; - uint8_t buffer[64]; -}; - -__device__ __constant__ sha256_word_type sha256_hash_constants[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; - -using sha512_word_type = uint64_t; - -struct sha512_intermediate_data { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint64_t hash_value[8] = {0x6a09e667f3bcc908, - 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, - 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, - 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, - 0x5be0cd19137e2179}; - uint8_t buffer[128]; -}; - -struct sha384_intermediate_data { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, - 0x629a292a367cd507, - 0x9159015a3070dd17, - 0x152fecd8f70e5939, - 0x67332667ffc00b31, - 0x8eb44a8768581511, - 0xdb0c2e0d64f98fa7, - 0x47b5481dbefa4fa4}; - uint8_t buffer[128]; -}; - -__device__ __constant__ sha512_word_type sha512_hash_constants[80] = { - 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, - 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, - 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, - 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, - 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, - 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, - 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, - 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, - 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, - 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, - 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, - 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, - 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, - 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, - 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, - 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, - 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, -}; - } // namespace detail } // namespace cudf diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index f9d45ba6aba..26589b30529 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -281,6 +281,90 @@ struct SHAHash : public crtp { } }; +struct sha1_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + uint8_t buffer[64]; +}; + +struct sha224_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + uint8_t buffer[64]; +}; + +struct sha256_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + uint8_t buffer[64]; +}; + +struct sha384_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4}; + uint8_t buffer[128]; +}; + +struct sha512_intermediate_data { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8] = {0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179}; + uint8_t buffer[128]; +}; + +__constant__ uint32_t sha256_hash_constants[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +__constant__ uint64_t sha512_hash_constants[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; + /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -493,7 +577,7 @@ struct SHA1Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha1_intermediate_data; // The word type used by this hash function - using sha_word_type = sha1_word_type; + using sha_word_type = uint32_t; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 64; // Digest size in bytes @@ -513,7 +597,7 @@ struct SHA224Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha224_intermediate_data; // The word type used by this hash function - using sha_word_type = sha256_word_type; + using sha_word_type = uint32_t; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 64; // Digest size in bytes. This is truncated from SHA-256. @@ -533,7 +617,7 @@ struct SHA256Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha256_intermediate_data; // The word type used by this hash function - using sha_word_type = sha256_word_type; + using sha_word_type = uint32_t; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 64; // Digest size in bytes @@ -553,7 +637,7 @@ struct SHA384Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha384_intermediate_data; // The word type used by this hash function - using sha_word_type = sha512_word_type; + using sha_word_type = uint64_t; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 128; // Digest size in bytes. This is truncated from SHA-512. @@ -573,7 +657,7 @@ struct SHA512Hash : SHAHash { // Intermediate data type storing the hash state using sha_intermediate_data = sha512_intermediate_data; // The word type used by this hash function - using sha_word_type = sha512_word_type; + using sha_word_type = uint64_t; // Number of bytes processed in each hash step static constexpr auto message_chunk_size = 128; // Digest size in bytes From d7cfbc5b73f7644db7f5ce525e66766682b78615 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 13:03:37 -0700 Subject: [PATCH 059/100] Fail on invalid hash functions. --- cpp/src/hash/hashing.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index f1670fadc41..b1287471934 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -124,7 +124,7 @@ std::unique_ptr hash(table_view const& input, case (hash_id::HASH_SHA256): return sha256_hash(input, stream, mr); case (hash_id::HASH_SHA384): return sha384_hash(input, stream, mr); case (hash_id::HASH_SHA512): return sha512_hash(input, stream, mr); - default: return nullptr; + default: CUDF_FAIL("Unsupported hash function."); } } From 8c6983dcb57d1f7ad1338d4f30f32a958c0be18c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 13:22:17 -0700 Subject: [PATCH 060/100] Use uint32_t consistently to avoid mixing signed/unsigned types. --- cpp/src/hash/sha_hash.cu | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 26589b30529..e1bf90cb64c 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -158,7 +158,7 @@ struct SHAHash : public crtp { { // Message length in bits. uint64_t const message_length_in_bits = (static_cast(hash_state.message_length)) << 3; - // Add a one bit flag to signal the end of the message + // Add a one bit flag (10000000) to signal the end of the message uint8_t constexpr end_of_message = 0x80; // 1 byte for the end of the message flag uint32_t constexpr end_of_message_size = 1; @@ -171,7 +171,7 @@ struct SHAHash : public crtp { // SHA-512 uses a 128-bit message length instead of a 64-bit message length // but this code does not support messages with lengths exceeding UINT64_MAX // bits. We always pad the upper 64 bits with zeros. - auto constexpr message_length_supported_size = sizeof(message_length_in_bits); + uint32_t constexpr message_length_supported_size = sizeof(message_length_in_bits); if (hash_state.buffer_length + Hasher::message_length_size + end_of_message_size <= Hasher::message_chunk_size) { @@ -579,11 +579,11 @@ struct SHA1Hash : SHAHash { // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; + static constexpr uint32_t message_chunk_size = 64; // Digest size in bytes - static constexpr auto digest_size = 40; + static constexpr uint32_t digest_size = 40; // Number of bytes used for the message length - static constexpr auto message_length_size = 8; + static constexpr uint32_t message_length_size = 8; void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { @@ -599,11 +599,11 @@ struct SHA224Hash : SHAHash { // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; + static constexpr uint32_t message_chunk_size = 64; // Digest size in bytes. This is truncated from SHA-256. - static constexpr auto digest_size = 56; + static constexpr uint32_t digest_size = 56; // Number of bytes used for the message length - static constexpr auto message_length_size = 8; + static constexpr uint32_t message_length_size = 8; void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { @@ -619,11 +619,11 @@ struct SHA256Hash : SHAHash { // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 64; + static constexpr uint32_t message_chunk_size = 64; // Digest size in bytes - static constexpr auto digest_size = 64; + static constexpr uint32_t digest_size = 64; // Number of bytes used for the message length - static constexpr auto message_length_size = 8; + static constexpr uint32_t message_length_size = 8; void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { @@ -639,11 +639,11 @@ struct SHA384Hash : SHAHash { // The word type used by this hash function using sha_word_type = uint64_t; // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 128; + static constexpr uint32_t message_chunk_size = 128; // Digest size in bytes. This is truncated from SHA-512. - static constexpr auto digest_size = 96; + static constexpr uint32_t digest_size = 96; // Number of bytes used for the message length - static constexpr auto message_length_size = 16; + static constexpr uint32_t message_length_size = 16; void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { @@ -659,11 +659,11 @@ struct SHA512Hash : SHAHash { // The word type used by this hash function using sha_word_type = uint64_t; // Number of bytes processed in each hash step - static constexpr auto message_chunk_size = 128; + static constexpr uint32_t message_chunk_size = 128; // Digest size in bytes - static constexpr auto digest_size = 128; + static constexpr uint32_t digest_size = 128; // Number of bytes used for the message length - static constexpr auto message_length_size = 16; + static constexpr uint32_t message_length_size = 16; void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) { From 590f8b36e58a1dc8da477bae9ff8aff134592e0d Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 13:37:12 -0700 Subject: [PATCH 061/100] Simplify word size. --- cpp/src/hash/sha_hash.cu | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index e1bf90cb64c..f141852dd68 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -235,7 +235,7 @@ struct SHAHash : public crtp { size_type, typename Hasher::sha_intermediate_data&) { - cudf_assert(false && "SHA unsupported type."); + cudf_assert(false && "Unsupported type for SHA hash."); } template Date: Tue, 21 Sep 2021 14:25:41 -0700 Subject: [PATCH 062/100] Minor improvements to constness. --- cpp/src/hash/sha_hash.cu | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index f141852dd68..dcabdc2569f 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -389,14 +389,14 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) // The rest of the 80 words are generated from the first 16 words. for (int i = 16; i < 80; i++) { - uint32_t temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = rotate_bits_left(temp, 1); + uint32_t const temp = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rotate_bits_left(temp, 1); } for (int i = 0; i < 80; i++) { uint32_t F; - uint32_t temp; uint32_t k; + uint32_t temp; switch (i / 20) { case 0: F = D ^ (B & (C ^ D)); @@ -459,10 +459,10 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) // The rest of the 64 words are generated from the first 16 words. for (int i = 16; i < 64; i++) { - uint32_t s0 = rotate_bits_right(words[i - 15], 7) ^ rotate_bits_right(words[i - 15], 18) ^ - (words[i - 15] >> 3); - uint32_t s1 = rotate_bits_right(words[i - 2], 17) ^ rotate_bits_right(words[i - 2], 19) ^ - (words[i - 2] >> 10); + uint32_t const s0 = rotate_bits_right(words[i - 15], 7) ^ rotate_bits_right(words[i - 15], 18) ^ + (words[i - 15] >> 3); + uint32_t const s1 = rotate_bits_right(words[i - 2], 17) ^ rotate_bits_right(words[i - 2], 19) ^ + (words[i - 2] >> 10); words[i] = words[i - 16] + s0 + words[i - 7] + s1; } @@ -525,10 +525,10 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) // The rest of the 80 words are generated from the first 16 words. for (int i = 16; i < 80; i++) { - uint64_t s0 = rotate_bits_right(words[i - 15], 1) ^ rotate_bits_right(words[i - 15], 8) ^ - (words[i - 15] >> 7); - uint64_t s1 = rotate_bits_right(words[i - 2], 19) ^ rotate_bits_right(words[i - 2], 61) ^ - (words[i - 2] >> 6); + uint64_t const s0 = rotate_bits_right(words[i - 15], 1) ^ rotate_bits_right(words[i - 15], 8) ^ + (words[i - 15] >> 7); + uint64_t const s1 = rotate_bits_right(words[i - 2], 19) ^ rotate_bits_right(words[i - 2], 61) ^ + (words[i - 2] >> 6); words[i] = words[i - 16] + s0 + words[i - 7] + s1; } @@ -686,8 +686,7 @@ std::unique_ptr sha_hash(table_view const& input, if (input.num_columns() == 0 || input.num_rows() == 0) { // Return the hash of a zero-length input. // TODO: This probably needs tested! - auto output = make_column_from_scalar(empty_result, input.num_rows(), stream, mr); - return output; + return make_column_from_scalar(empty_result, input.num_rows(), stream, mr); } // Accepts string and fixed width columns. From d9ae7f134d700fbb61f9acb364fb3d6ce1153d88 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 21 Sep 2021 16:26:20 -0700 Subject: [PATCH 063/100] Add tests for empty tables. --- cpp/src/hash/sha_hash.cu | 1 - cpp/tests/hashing/hash_test.cpp | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index dcabdc2569f..3d7b086da07 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -685,7 +685,6 @@ std::unique_ptr sha_hash(table_view const& input, { if (input.num_columns() == 0 || input.num_rows() == 0) { // Return the hash of a zero-length input. - // TODO: This probably needs tested! return make_column_from_scalar(empty_result, input.num_rows(), stream, mr); } diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 999baa955af..4fc2162b465 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ +#include #include #include #include +#include #include #include @@ -717,6 +719,20 @@ TYPED_TEST(MD5HashTestFloatTyped, TestListExtremes) class SHA1HashTest : public cudf::test::BaseFixture { }; +TEST_F(SHA1HashTest, EmptyTable) +{ + auto const empty_table = cudf::table_view{}; + auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); + auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); + EXPECT_EQ(empty_column->size(), output_empty_table->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); + + auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; + auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); + EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); +} + TEST_F(SHA1HashTest, MultiValue) { strings_column_wrapper const strings_col( @@ -880,6 +896,20 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) class SHA224HashTest : public cudf::test::BaseFixture { }; +TEST_F(SHA224HashTest, EmptyTable) +{ + auto const empty_table = cudf::table_view{}; + auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); + auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); + EXPECT_EQ(empty_column->size(), output_empty_table->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); + + auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; + auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); + EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); +} + TEST_F(SHA224HashTest, MultiValue) { strings_column_wrapper const strings_col( @@ -1045,6 +1075,20 @@ TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) class SHA256HashTest : public cudf::test::BaseFixture { }; +TEST_F(SHA256HashTest, EmptyTable) +{ + auto const empty_table = cudf::table_view{}; + auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); + auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); + EXPECT_EQ(empty_column->size(), output_empty_table->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); + + auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; + auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); + EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); +} + TEST_F(SHA256HashTest, MultiValue) { strings_column_wrapper const strings_col( @@ -1210,6 +1254,20 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) class SHA384HashTest : public cudf::test::BaseFixture { }; +TEST_F(SHA384HashTest, EmptyTable) +{ + auto const empty_table = cudf::table_view{}; + auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); + auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); + EXPECT_EQ(empty_column->size(), output_empty_table->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); + + auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; + auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); + EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); +} + TEST_F(SHA384HashTest, MultiValue) { strings_column_wrapper const strings_col( @@ -1391,6 +1449,20 @@ TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) class SHA512HashTest : public cudf::test::BaseFixture { }; +TEST_F(SHA512HashTest, EmptyTable) +{ + auto const empty_table = cudf::table_view{}; + auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); + auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); + EXPECT_EQ(empty_column->size(), output_empty_table->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); + + auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; + auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); + EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); +} + TEST_F(SHA512HashTest, MultiValue) { strings_column_wrapper const strings_col( From 4e8fdf3ca89a051a5427ba5da9c9a42024d4f93f Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 22 Sep 2021 07:52:41 -0700 Subject: [PATCH 064/100] Enable debug mode on sha_hash.cu so that CI can compile. --- cpp/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 324f48133ec..63c09f3a7e6 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -459,6 +459,8 @@ set_target_properties(cudf INTERFACE_POSITION_INDEPENDENT_CODE ON ) +set_source_files_properties(src/hash/sha_hash.cu PROPERTIES COMPILE_OPTIONS "-G") + target_compile_options(cudf PRIVATE "$<$:${CUDF_CXX_FLAGS}>" "$<$:${CUDF_CUDA_FLAGS}>" From c47945d93c2a5bc6074f4cd29d6699f732f344f9 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 14:55:35 -0700 Subject: [PATCH 065/100] Rename intermediate data to hash state. --- cpp/src/hash/sha_hash.cu | 259 ++++++++++++++++++--------------------- 1 file changed, 119 insertions(+), 140 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 3d7b086da07..a23fab6f927 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -96,7 +96,7 @@ struct crtp { }; template -struct SHAHash : public crtp { +struct HashBase : public crtp { /** * @brief Execute SHA on input data chunks. * @@ -106,43 +106,42 @@ struct SHAHash : public crtp { template void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len, - typename Hasher::sha_intermediate_data& hash_state) + typename Hasher::hash_state& state) { - hash_state.message_length += len; + state.message_length += len; - if (hash_state.buffer_length + len < Hasher::message_chunk_size) { + if (state.buffer_length + len < Hasher::message_chunk_size) { // The buffer will not be filled by this data. We copy the new data into // the buffer but do not trigger a hash step yet. - memcpy(hash_state.buffer + hash_state.buffer_length, data, len); - hash_state.buffer_length += len; + memcpy(state.buffer + state.buffer_length, data, len); + state.buffer_length += len; } else { // The buffer will be filled by this data. Copy a chunk of the data to fill // the buffer and trigger a hash step. - uint32_t copylen = Hasher::message_chunk_size - hash_state.buffer_length; - memcpy(hash_state.buffer + hash_state.buffer_length, data, copylen); - this->underlying().hash_step(hash_state); + uint32_t copylen = Hasher::message_chunk_size - state.buffer_length; + memcpy(state.buffer + state.buffer_length, data, copylen); + this->underlying().hash_step(state); // Take buffer-sized chunks of the data and do a hash step on each chunk. while (len > Hasher::message_chunk_size + copylen) { - memcpy(hash_state.buffer, data + copylen, Hasher::message_chunk_size); - this->underlying().hash_step(hash_state); + memcpy(state.buffer, data + copylen, Hasher::message_chunk_size); + this->underlying().hash_step(state); copylen += Hasher::message_chunk_size; } // The remaining data chunk does not fill the buffer. We copy the data into // the buffer but do not trigger a hash step yet. - memcpy(hash_state.buffer, data + copylen, len - copylen); - hash_state.buffer_length = len - copylen; + memcpy(state.buffer, data + copylen, len - copylen); + state.buffer_length = len - copylen; } } template - void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key, - typename Hasher::sha_intermediate_data& hash_state) + void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key, typename Hasher::hash_state& state) { uint8_t const* data = reinterpret_cast(&key); uint32_t constexpr len = sizeof(T); - process(data, len, hash_state); + process(data, len, state); } /** @@ -153,58 +152,55 @@ struct SHAHash : public crtp { * the final hash step. */ template - void CUDA_DEVICE_CALLABLE finalize(typename Hasher::sha_intermediate_data& hash_state, - char* result_location) + void CUDA_DEVICE_CALLABLE finalize(typename Hasher::hash_state& state, char* result_location) { // Message length in bits. - uint64_t const message_length_in_bits = (static_cast(hash_state.message_length)) << 3; + uint64_t const message_length_in_bits = (static_cast(state.message_length)) << 3; // Add a one bit flag (10000000) to signal the end of the message uint8_t constexpr end_of_message = 0x80; // 1 byte for the end of the message flag uint32_t constexpr end_of_message_size = 1; - thrust::fill_n(thrust::seq, - hash_state.buffer + hash_state.buffer_length, - end_of_message_size, - end_of_message); + thrust::fill_n( + thrust::seq, state.buffer + state.buffer_length, end_of_message_size, end_of_message); // SHA-512 uses a 128-bit message length instead of a 64-bit message length // but this code does not support messages with lengths exceeding UINT64_MAX // bits. We always pad the upper 64 bits with zeros. uint32_t constexpr message_length_supported_size = sizeof(message_length_in_bits); - if (hash_state.buffer_length + Hasher::message_length_size + end_of_message_size <= + if (state.buffer_length + Hasher::message_length_size + end_of_message_size <= Hasher::message_chunk_size) { // Fill the remainder of the buffer with zeros up to the space reserved // for the message length. The message length fits in this hash step. thrust::fill(thrust::seq, - hash_state.buffer + hash_state.buffer_length + end_of_message_size, - hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, + state.buffer + state.buffer_length + end_of_message_size, + state.buffer + Hasher::message_chunk_size - message_length_supported_size, 0x00); } else { // Fill the remainder of the buffer with zeros. The message length doesn't // fit and will be processed in a subsequent hash step comprised of only // zeros followed by the message length. thrust::fill(thrust::seq, - hash_state.buffer + hash_state.buffer_length + end_of_message_size, - hash_state.buffer + Hasher::message_chunk_size, + state.buffer + state.buffer_length + end_of_message_size, + state.buffer + Hasher::message_chunk_size, 0x00); - this->underlying().hash_step(hash_state); + this->underlying().hash_step(state); // Fill the entire message with zeros up to the final bytes reserved for // the message length. thrust::fill_n(thrust::seq, - hash_state.buffer, + state.buffer, Hasher::message_chunk_size - message_length_supported_size, 0x00); } // Convert the 64-bit message length from little-endian to big-endian. uint64_t const full_length_flipped = swap_endian(message_length_in_bits); - memcpy(hash_state.buffer + Hasher::message_chunk_size - message_length_supported_size, + memcpy(state.buffer + Hasher::message_chunk_size - message_length_supported_size, reinterpret_cast(&full_length_flipped), message_length_supported_size); - this->underlying().hash_step(hash_state); + this->underlying().hash_step(state); // Each byte in the word generates two bytes in the hexadecimal string digest. // SHA-224 and SHA-384 digests are truncated because their digest does not @@ -213,7 +209,7 @@ struct SHAHash : public crtp { Hasher::digest_size / (2 * sizeof(typename Hasher::sha_word_type)); for (int i = 0; i < num_words_to_copy; i++) { // Convert word representation from big-endian to little-endian. - typename Hasher::sha_word_type flipped = swap_endian(hash_state.hash_value[i]); + typename Hasher::sha_word_type flipped = swap_endian(state.hash_value[i]); if constexpr (std::is_same_v) { uint32ToLowercaseHexString(flipped, result_location + (8 * i)); } else if constexpr (std::is_same_v) { @@ -231,9 +227,7 @@ struct SHAHash : public crtp { typename Hasher = HasherT, typename std::enable_if_t<(!is_fixed_width() || is_chrono()) && !std::is_same_v>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view, - size_type, - typename Hasher::sha_intermediate_data&) + void CUDA_DEVICE_CALLABLE operator()(column_device_view, size_type, typename Hasher::hash_state&) { cudf_assert(false && "Unsupported type for SHA hash."); } @@ -243,16 +237,16 @@ struct SHAHash : public crtp { typename std::enable_if_t()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) + typename Hasher::hash_state& state) { T const& key = col.element(row_index); if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); - process_fixed_width(nan, hash_state); + process_fixed_width(nan, state); } else if (key == T{0.0}) { - process_fixed_width(T{0.0}, hash_state); + process_fixed_width(T{0.0}, state); } else { - process_fixed_width(key, hash_state); + process_fixed_width(key, state); } } @@ -262,9 +256,9 @@ struct SHAHash : public crtp { !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) + typename Hasher::hash_state& state) { - process_fixed_width(col.element(row_index), hash_state); + process_fixed_width(col.element(row_index), state); } template { typename std::enable_if_t>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(column_device_view col, size_type row_index, - typename Hasher::sha_intermediate_data& hash_state) + typename Hasher::hash_state& state) { string_view key = col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); uint32_t const len = static_cast(key.size_bytes()); - process(data, len, hash_state); + process(data, len, state); } }; -struct sha1_intermediate_data { +struct sha1_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; uint8_t buffer[64]; }; -struct sha224_intermediate_data { +struct sha224_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint32_t hash_value[8] = { @@ -296,7 +290,7 @@ struct sha224_intermediate_data { uint8_t buffer[64]; }; -struct sha256_intermediate_data { +struct sha256_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint32_t hash_value[8] = { @@ -304,7 +298,7 @@ struct sha256_intermediate_data { uint8_t buffer[64]; }; -struct sha384_intermediate_data { +struct sha384_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, @@ -318,7 +312,7 @@ struct sha384_intermediate_data { uint8_t buffer[128]; }; -struct sha512_intermediate_data { +struct sha512_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint64_t hash_value[8] = {0x6a09e667f3bcc908, @@ -369,19 +363,19 @@ __constant__ uint64_t sha512_hash_constants[80] = { * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. */ -template -void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) +template +void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) { - uint32_t A = hash_state.hash_value[0]; - uint32_t B = hash_state.hash_value[1]; - uint32_t C = hash_state.hash_value[2]; - uint32_t D = hash_state.hash_value[3]; - uint32_t E = hash_state.hash_value[4]; + uint32_t A = state.hash_value[0]; + uint32_t B = state.hash_value[1]; + uint32_t C = state.hash_value[2]; + uint32_t D = state.hash_value[3]; + uint32_t E = state.hash_value[4]; uint32_t words[80]; // The 512-bit message buffer fills the first 16 words. - memcpy(&words[0], hash_state.buffer, sizeof(words[0]) * 16); + memcpy(&words[0], state.buffer, sizeof(words[0]) * 16); for (int i = 0; i < 16; i++) { // Convert word representation from little-endian to big-endian. words[i] = swap_endian(words[i]); @@ -423,35 +417,35 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(sha_intermediate_data& hash_state) A = temp; } - hash_state.hash_value[0] += A; - hash_state.hash_value[1] += B; - hash_state.hash_value[2] += C; - hash_state.hash_value[3] += D; - hash_state.hash_value[4] += E; + state.hash_value[0] += A; + state.hash_value[1] += B; + state.hash_value[2] += C; + state.hash_value[3] += D; + state.hash_value[4] += E; - hash_state.buffer_length = 0; + state.buffer_length = 0; } /** * @brief Core SHA-256 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. */ -template -void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) +template +void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) { - uint32_t A = hash_state.hash_value[0]; - uint32_t B = hash_state.hash_value[1]; - uint32_t C = hash_state.hash_value[2]; - uint32_t D = hash_state.hash_value[3]; - uint32_t E = hash_state.hash_value[4]; - uint32_t F = hash_state.hash_value[5]; - uint32_t G = hash_state.hash_value[6]; - uint32_t H = hash_state.hash_value[7]; + uint32_t A = state.hash_value[0]; + uint32_t B = state.hash_value[1]; + uint32_t C = state.hash_value[2]; + uint32_t D = state.hash_value[3]; + uint32_t E = state.hash_value[4]; + uint32_t F = state.hash_value[5]; + uint32_t G = state.hash_value[6]; + uint32_t H = state.hash_value[7]; uint32_t words[64]; // The 512-bit message buffer fills the first 16 words. - memcpy(&words[0], hash_state.buffer, sizeof(words[0]) * 16); + memcpy(&words[0], state.buffer, sizeof(words[0]) * 16); for (int i = 0; i < 16; i++) { // Convert word representation from little-endian to big-endian. words[i] = swap_endian(words[i]); @@ -486,38 +480,38 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(sha_intermediate_data& hash_state) A = temp1 + temp2; } - hash_state.hash_value[0] += A; - hash_state.hash_value[1] += B; - hash_state.hash_value[2] += C; - hash_state.hash_value[3] += D; - hash_state.hash_value[4] += E; - hash_state.hash_value[5] += F; - hash_state.hash_value[6] += G; - hash_state.hash_value[7] += H; + state.hash_value[0] += A; + state.hash_value[1] += B; + state.hash_value[2] += C; + state.hash_value[3] += D; + state.hash_value[4] += E; + state.hash_value[5] += F; + state.hash_value[6] += G; + state.hash_value[7] += H; - hash_state.buffer_length = 0; + state.buffer_length = 0; } /** * @brief Core SHA-512 algorithm implementation. Processes a single 1024-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. */ -template -void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) +template +void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) { - uint64_t A = hash_state.hash_value[0]; - uint64_t B = hash_state.hash_value[1]; - uint64_t C = hash_state.hash_value[2]; - uint64_t D = hash_state.hash_value[3]; - uint64_t E = hash_state.hash_value[4]; - uint64_t F = hash_state.hash_value[5]; - uint64_t G = hash_state.hash_value[6]; - uint64_t H = hash_state.hash_value[7]; + uint64_t A = state.hash_value[0]; + uint64_t B = state.hash_value[1]; + uint64_t C = state.hash_value[2]; + uint64_t D = state.hash_value[3]; + uint64_t E = state.hash_value[4]; + uint64_t F = state.hash_value[5]; + uint64_t G = state.hash_value[6]; + uint64_t H = state.hash_value[7]; uint64_t words[80]; // The 1024-bit message buffer fills the first 16 words. - memcpy(&words[0], hash_state.buffer, sizeof(words[0]) * 16); + memcpy(&words[0], state.buffer, sizeof(words[0]) * 16); for (int i = 0; i < 16; i++) { // Convert word representation from little-endian to big-endian. words[i] = swap_endian(words[i]); @@ -552,21 +546,21 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(sha_intermediate_data& hash_state) A = temp1 + temp2; } - hash_state.hash_value[0] += A; - hash_state.hash_value[1] += B; - hash_state.hash_value[2] += C; - hash_state.hash_value[3] += D; - hash_state.hash_value[4] += E; - hash_state.hash_value[5] += F; - hash_state.hash_value[6] += G; - hash_state.hash_value[7] += H; + state.hash_value[0] += A; + state.hash_value[1] += B; + state.hash_value[2] += C; + state.hash_value[3] += D; + state.hash_value[4] += E; + state.hash_value[5] += F; + state.hash_value[6] += G; + state.hash_value[7] += H; - hash_state.buffer_length = 0; + state.buffer_length = 0; } -struct SHA1Hash : SHAHash { +struct SHA1Hash : HashBase { // Intermediate data type storing the hash state - using sha_intermediate_data = sha1_intermediate_data; + using hash_state = sha1_hash_state; // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step @@ -576,17 +570,14 @@ struct SHA1Hash : SHAHash { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) - { - sha1_hash_step(hash_state); - } + void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha1_hash_step(state); } - sha_intermediate_data hash_state; + hash_state state; }; -struct SHA224Hash : SHAHash { +struct SHA224Hash : HashBase { // Intermediate data type storing the hash state - using sha_intermediate_data = sha224_intermediate_data; + using hash_state = sha224_hash_state; // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step @@ -596,17 +587,14 @@ struct SHA224Hash : SHAHash { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) - { - sha256_hash_step(hash_state); - } + void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha256_hash_step(state); } - sha_intermediate_data hash_state; + hash_state state; }; -struct SHA256Hash : SHAHash { +struct SHA256Hash : HashBase { // Intermediate data type storing the hash state - using sha_intermediate_data = sha256_intermediate_data; + using hash_state = sha256_hash_state; // The word type used by this hash function using sha_word_type = uint32_t; // Number of bytes processed in each hash step @@ -616,17 +604,14 @@ struct SHA256Hash : SHAHash { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) - { - sha256_hash_step(hash_state); - } + void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha256_hash_step(state); } - sha_intermediate_data hash_state; + hash_state state; }; -struct SHA384Hash : SHAHash { +struct SHA384Hash : HashBase { // Intermediate data type storing the hash state - using sha_intermediate_data = sha384_intermediate_data; + using hash_state = sha384_hash_state; // The word type used by this hash function using sha_word_type = uint64_t; // Number of bytes processed in each hash step @@ -636,17 +621,14 @@ struct SHA384Hash : SHAHash { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 16; - void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) - { - sha512_hash_step(hash_state); - } + void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha512_hash_step(state); } - sha_intermediate_data hash_state; + hash_state state; }; -struct SHA512Hash : SHAHash { +struct SHA512Hash : HashBase { // Intermediate data type storing the hash state - using sha_intermediate_data = sha512_intermediate_data; + using hash_state = sha512_hash_state; // The word type used by this hash function using sha_word_type = uint64_t; // Number of bytes processed in each hash step @@ -656,12 +638,9 @@ struct SHA512Hash : SHAHash { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 16; - void CUDA_DEVICE_CALLABLE hash_step(sha_intermediate_data& hash_state) - { - sha512_hash_step(hash_state); - } + void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha512_hash_step(state); } - sha_intermediate_data hash_state; + hash_state state; }; /** @@ -722,11 +701,11 @@ std::unique_ptr sha_hash(table_view const& input, hasher, device_input.column(col_index), row_index, - hasher.hash_state); + hasher.state); } } auto const result_location = d_chars + (row_index * Hasher::digest_size); - hasher.finalize(hasher.hash_state, result_location); + hasher.finalize(hasher.state, result_location); }); return make_strings_column( From b37e5f0e95d93d08e6a849d14fd756362a2f5589 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 15:09:09 -0700 Subject: [PATCH 066/100] Use HashDispatcher for type dispatch. --- cpp/src/hash/sha_hash.cu | 66 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index a23fab6f927..786ad8cd7d6 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -104,10 +104,9 @@ struct HashBase : public crtp { * when the buffer is filled up to message_chunk_size bytes. */ template - void CUDA_DEVICE_CALLABLE process(uint8_t const* data, - uint32_t len, - typename Hasher::hash_state& state) + void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len) { + auto& state = this->underlying().state; state.message_length += len; if (state.buffer_length + len < Hasher::message_chunk_size) { @@ -136,12 +135,12 @@ struct HashBase : public crtp { } } - template - void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key, typename Hasher::hash_state& state) + template + void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key) { uint8_t const* data = reinterpret_cast(&key); uint32_t constexpr len = sizeof(T); - process(data, len, state); + process(data, len); } /** @@ -152,8 +151,9 @@ struct HashBase : public crtp { * the final hash step. */ template - void CUDA_DEVICE_CALLABLE finalize(typename Hasher::hash_state& state, char* result_location) + void CUDA_DEVICE_CALLABLE finalize(char* result_location) { + auto& state = this->underlying().state; // Message length in bits. uint64_t const message_length_in_bits = (static_cast(state.message_length)) << 3; // Add a one bit flag (10000000) to signal the end of the message @@ -222,56 +222,50 @@ struct HashBase : public crtp { } } }; +}; + +template +struct HashDispatcher { + Hasher* hash; + column_device_view col; template () || is_chrono()) && !std::is_same_v>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view, size_type, typename Hasher::hash_state&) + void CUDA_DEVICE_CALLABLE operator()(size_type) { - cudf_assert(false && "Unsupported type for SHA hash."); + cudf_assert(false && "Unsupported type for hash function."); } - template ()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - typename Hasher::hash_state& state) + template ()>* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { T const& key = col.element(row_index); if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); - process_fixed_width(nan, state); + hash->process_fixed_width(nan); } else if (key == T{0.0}) { - process_fixed_width(T{0.0}, state); + hash->process_fixed_width(T{0.0}); } else { - process_fixed_width(key, state); + hash->process_fixed_width(key); } } template () && !is_floating_point() && !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - typename Hasher::hash_state& state) + void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { - process_fixed_width(col.element(row_index), state); + hash->process_fixed_width(col.element(row_index)); } - template >* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(column_device_view col, - size_type row_index, - typename Hasher::hash_state& state) + template >* = nullptr> + void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { string_view key = col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); uint32_t const len = static_cast(key.size_bytes()); - process(data, len, state); + hash->process(data, len); } }; @@ -696,16 +690,14 @@ std::unique_ptr sha_hash(table_view const& input, Hasher hasher = Hasher{}; for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { + auto const& col = device_input.column(col_index); + HashDispatcher hash_dispatcher{&hasher, col}; cudf::type_dispatcher( - device_input.column(col_index).type(), - hasher, - device_input.column(col_index), - row_index, - hasher.state); + col.type(), hash_dispatcher, row_index); } } auto const result_location = d_chars + (row_index * Hasher::digest_size); - hasher.finalize(hasher.state, result_location); + hasher.finalize(result_location); }); return make_strings_column( From 607aaad36c82d722dfbb37e46b8eb3d4ddd1b1bd Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 16:58:57 -0700 Subject: [PATCH 067/100] Cleanup of templates and class/variable names. --- cpp/src/hash/sha_hash.cu | 72 +++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 786ad8cd7d6..102c359009a 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -95,15 +95,14 @@ struct crtp { CUDA_DEVICE_CALLABLE T const& underlying() const { return static_cast(*this); } }; -template -struct HashBase : public crtp { +template +struct HashBase : public crtp { /** * @brief Execute SHA on input data chunks. * * This accepts arbitrary data, handles it as bytes, and calls the hash step * when the buffer is filled up to message_chunk_size bytes. */ - template void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len) { auto& state = this->underlying().state; @@ -150,7 +149,6 @@ struct HashBase : public crtp { * the message length (in another step of the hash, if needed), and performs * the final hash step. */ - template void CUDA_DEVICE_CALLABLE finalize(char* result_location) { auto& state = this->underlying().state; @@ -225,8 +223,8 @@ struct HashBase : public crtp { }; template -struct HashDispatcher { - Hasher* hash; +struct HasherDispatcher { + Hasher* hasher; column_device_view col; template (row_index); if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); - hash->process_fixed_width(nan); + hasher->process_fixed_width(nan); } else if (key == T{0.0}) { - hash->process_fixed_width(T{0.0}); + hasher->process_fixed_width(T{0.0}); } else { - hash->process_fixed_width(key); + hasher->process_fixed_width(key); } } @@ -256,7 +254,7 @@ struct HashDispatcher { !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { - hash->process_fixed_width(col.element(row_index)); + hasher->process_fixed_width(col.element(row_index)); } template >* = nullptr> @@ -265,7 +263,7 @@ struct HashDispatcher { string_view key = col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); uint32_t const len = static_cast(key.size_bytes()); - hash->process(data, len); + hasher->process(data, len); } }; @@ -360,12 +358,6 @@ __constant__ uint64_t sha512_hash_constants[80] = { template void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) { - uint32_t A = state.hash_value[0]; - uint32_t B = state.hash_value[1]; - uint32_t C = state.hash_value[2]; - uint32_t D = state.hash_value[3]; - uint32_t E = state.hash_value[4]; - uint32_t words[80]; // The 512-bit message buffer fills the first 16 words. @@ -381,6 +373,12 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) words[i] = rotate_bits_left(temp, 1); } + uint32_t A = state.hash_value[0]; + uint32_t B = state.hash_value[1]; + uint32_t C = state.hash_value[2]; + uint32_t D = state.hash_value[3]; + uint32_t E = state.hash_value[4]; + for (int i = 0; i < 80; i++) { uint32_t F; uint32_t k; @@ -427,15 +425,6 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) template void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) { - uint32_t A = state.hash_value[0]; - uint32_t B = state.hash_value[1]; - uint32_t C = state.hash_value[2]; - uint32_t D = state.hash_value[3]; - uint32_t E = state.hash_value[4]; - uint32_t F = state.hash_value[5]; - uint32_t G = state.hash_value[6]; - uint32_t H = state.hash_value[7]; - uint32_t words[64]; // The 512-bit message buffer fills the first 16 words. @@ -454,6 +443,15 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) words[i] = words[i - 16] + s0 + words[i - 7] + s1; } + uint32_t A = state.hash_value[0]; + uint32_t B = state.hash_value[1]; + uint32_t C = state.hash_value[2]; + uint32_t D = state.hash_value[3]; + uint32_t E = state.hash_value[4]; + uint32_t F = state.hash_value[5]; + uint32_t G = state.hash_value[6]; + uint32_t H = state.hash_value[7]; + for (int i = 0; i < 64; i++) { uint32_t const s1 = rotate_bits_right(E, 6) ^ rotate_bits_right(E, 11) ^ rotate_bits_right(E, 25); @@ -493,15 +491,6 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) template void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) { - uint64_t A = state.hash_value[0]; - uint64_t B = state.hash_value[1]; - uint64_t C = state.hash_value[2]; - uint64_t D = state.hash_value[3]; - uint64_t E = state.hash_value[4]; - uint64_t F = state.hash_value[5]; - uint64_t G = state.hash_value[6]; - uint64_t H = state.hash_value[7]; - uint64_t words[80]; // The 1024-bit message buffer fills the first 16 words. @@ -520,6 +509,15 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) words[i] = words[i - 16] + s0 + words[i - 7] + s1; } + uint64_t A = state.hash_value[0]; + uint64_t B = state.hash_value[1]; + uint64_t C = state.hash_value[2]; + uint64_t D = state.hash_value[3]; + uint64_t E = state.hash_value[4]; + uint64_t F = state.hash_value[5]; + uint64_t G = state.hash_value[6]; + uint64_t H = state.hash_value[7]; + for (int i = 0; i < 80; i++) { uint64_t const s1 = rotate_bits_right(E, 14) ^ rotate_bits_right(E, 18) ^ rotate_bits_right(E, 41); @@ -691,9 +689,9 @@ std::unique_ptr sha_hash(table_view const& input, for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { if (device_input.column(col_index).is_valid(row_index)) { auto const& col = device_input.column(col_index); - HashDispatcher hash_dispatcher{&hasher, col}; + HasherDispatcher hasher_dispatcher{&hasher, col}; cudf::type_dispatcher( - col.type(), hash_dispatcher, row_index); + col.type(), hasher_dispatcher, row_index); } } auto const result_location = d_chars + (row_index * Hasher::digest_size); From 2779a96f226f46165965277d4fe393b8b089e354 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 17:06:42 -0700 Subject: [PATCH 068/100] Reorganize headers, update error message. --- cpp/src/hash/sha_hash.cu | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 102c359009a..1bb87a2d213 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -15,21 +15,23 @@ */ #include #include +#include #include #include #include #include #include -#include #include #include -#include #include #include #include +#include +#include + namespace cudf { namespace detail { @@ -664,7 +666,7 @@ std::unique_ptr sha_hash(table_view const& input, CUDF_EXPECTS( std::all_of( input.begin(), input.end(), [](auto const& col) { return sha_type_check(col.type()); }), - "SHA unsupported column type"); + "Unsupported column type for hash function."); // Result column allocation and creation auto begin = thrust::make_constant_iterator(Hasher::digest_size); From 93b6f54290e1a3f7949f05657fcd5de19421a7fd Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 17:26:46 -0700 Subject: [PATCH 069/100] Generate null mask for all hash values. --- cpp/src/hash/sha_hash.cu | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 1bb87a2d213..61bde507be6 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -678,7 +678,8 @@ std::unique_ptr sha_hash(table_view const& input, auto chars_view = chars_column->mutable_view(); auto d_chars = chars_view.template data(); - rmm::device_buffer null_mask{0, stream, mr}; + // Build an output null mask from the logical AND of all input columns' null masks. + rmm::device_buffer null_mask{cudf::detail::bitmask_and(input, stream)}; auto const device_input = table_device_view::create(input, stream); @@ -688,9 +689,8 @@ std::unique_ptr sha_hash(table_view const& input, thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { Hasher hasher = Hasher{}; - for (int col_index = 0; col_index < device_input.num_columns(); col_index++) { - if (device_input.column(col_index).is_valid(row_index)) { - auto const& col = device_input.column(col_index); + for (auto const& col : device_input) { + if (col.is_valid(row_index)) { HasherDispatcher hasher_dispatcher{&hasher, col}; cudf::type_dispatcher( col.type(), hasher_dispatcher, row_index); From f850e5f28f535955d1100a713dca1f3b72586968 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 27 Sep 2021 18:03:20 -0700 Subject: [PATCH 070/100] Update tests for new null behavior. --- cpp/tests/hashing/hash_test.cpp | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 4fc2162b465..b6e6500b639 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -805,19 +805,19 @@ TEST_F(SHA1HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 1}); // empty string is equivalent to null + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 1, 0}); fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -984,19 +984,19 @@ TEST_F(SHA224HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 1}); // empty string is equivalent to null + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 1, 0}); fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1163,19 +1163,19 @@ TEST_F(SHA256HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 1}); // empty string is equivalent to null + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 1, 0}); fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1358,19 +1358,19 @@ TEST_F(SHA384HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 1}); // empty string is equivalent to null + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 1, 0}); fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1553,19 +1553,19 @@ TEST_F(SHA512HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 1}); // empty string is equivalent to null + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 1, 0}); fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 1, 1}); + {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); + fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); From 1c6cc2bfba76ecfa264b15adba17b1e0ce870a18 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 4 Oct 2021 11:47:02 -0700 Subject: [PATCH 071/100] Simplify SFINAE. --- cpp/src/hash/sha_hash.cu | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 61bde507be6..039e53e63d7 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -237,28 +237,25 @@ struct HasherDispatcher { cudf_assert(false && "Unsupported type for hash function."); } - template ()>* = nullptr> + template () && !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { T const& key = col.element(row_index); - if (isnan(key)) { - T nan = std::numeric_limits::quiet_NaN(); - hasher->process_fixed_width(nan); - } else if (key == T{0.0}) { - hasher->process_fixed_width(T{0.0}); + if constexpr (is_floating_point()) { + if (isnan(key)) { + T nan = std::numeric_limits::quiet_NaN(); + hasher->process_fixed_width(nan); + } else if (key == T{0.0}) { + hasher->process_fixed_width(T{0.0}); + } else { + hasher->process_fixed_width(key); + } } else { hasher->process_fixed_width(key); } } - template () && !is_floating_point() && - !is_chrono()>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(size_type row_index) - { - hasher->process_fixed_width(col.element(row_index)); - } - template >* = nullptr> void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { From 2374df4ae3e8bccd88e2d300737b824d2f8bfea1 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Fri, 8 Oct 2021 08:42:28 -0700 Subject: [PATCH 072/100] Add benchmarks for SHA functions. --- cpp/benchmarks/hashing/hash_benchmark.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/benchmarks/hashing/hash_benchmark.cpp b/cpp/benchmarks/hashing/hash_benchmark.cpp index 77b10399693..6aa831cb445 100644 --- a/cpp/benchmarks/hashing/hash_benchmark.cpp +++ b/cpp/benchmarks/hashing/hash_benchmark.cpp @@ -49,3 +49,8 @@ HASH_BENCHMARK_DEFINE(HASH_MURMUR3) HASH_BENCHMARK_DEFINE(HASH_MD5) HASH_BENCHMARK_DEFINE(HASH_SERIAL_MURMUR3) HASH_BENCHMARK_DEFINE(HASH_SPARK_MURMUR3) +HASH_BENCHMARK_DEFINE(HASH_SHA1) +HASH_BENCHMARK_DEFINE(HASH_SHA224) +HASH_BENCHMARK_DEFINE(HASH_SHA256) +HASH_BENCHMARK_DEFINE(HASH_SHA384) +HASH_BENCHMARK_DEFINE(HASH_SHA512) From c0381b1b4cceb7f4114236c4ab50357b0b78dea8 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Fri, 8 Oct 2021 08:55:38 -0700 Subject: [PATCH 073/100] Limit range to reduce memory usage for SHA512. --- cpp/benchmarks/hashing/hash_benchmark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/benchmarks/hashing/hash_benchmark.cpp b/cpp/benchmarks/hashing/hash_benchmark.cpp index 6aa831cb445..711c38e4d91 100644 --- a/cpp/benchmarks/hashing/hash_benchmark.cpp +++ b/cpp/benchmarks/hashing/hash_benchmark.cpp @@ -41,7 +41,7 @@ static void BM_hash(benchmark::State& state, cudf::hash_id hid) (::benchmark::State & st) { BM_hash(st, cudf::hash_id::name); } \ BENCHMARK_REGISTER_F(HashBenchmark, name) \ ->RangeMultiplier(4) \ - ->Ranges({{1 << 14, 1 << 24}}) \ + ->Ranges({{1 << 14, 1 << 23}}) \ ->UseManualTime() \ ->Unit(benchmark::kMillisecond); From d1936f30c337ed341463d35647aa3fcd4b30eede Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 18 Oct 2021 17:15:46 -0700 Subject: [PATCH 074/100] Add SHA methods to Python. --- python/cudf/cudf/_lib/hash.pyx | 10 ++++++++++ python/cudf/cudf/core/dataframe.py | 5 +++++ python/cudf/cudf/core/series.py | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/python/cudf/cudf/_lib/hash.pyx b/python/cudf/cudf/_lib/hash.pyx index 9b34a049cac..55fecc4cc84 100644 --- a/python/cudf/cudf/_lib/hash.pyx +++ b/python/cudf/cudf/_lib/hash.pyx @@ -64,6 +64,16 @@ def hash(source_table, str method, object initial_hash=None, int seed=0): c_hash_function = libcudf_types.hash_id.HASH_MURMUR3 elif method == "md5": c_hash_function = libcudf_types.hash_id.HASH_MD5 + elif method == "sha1": + c_hash_function = libcudf_types.hash_id.HASH_SHA1 + elif method == "sha224": + c_hash_function = libcudf_types.hash_id.HASH_SHA224 + elif method == "sha256": + c_hash_function = libcudf_types.hash_id.HASH_SHA256 + elif method == "sha384": + c_hash_function = libcudf_types.hash_id.HASH_SHA384 + elif method == "sha512": + c_hash_function = libcudf_types.hash_id.HASH_SHA512 else: raise ValueError(f"Unsupported hash function: {method}") with nogil: diff --git a/python/cudf/cudf/core/dataframe.py b/python/cudf/cudf/core/dataframe.py index 2e5e52d6eba..ea81e4381c7 100644 --- a/python/cudf/cudf/core/dataframe.py +++ b/python/cudf/cudf/core/dataframe.py @@ -4405,6 +4405,11 @@ def hash_columns(self, columns=None, method="murmur3"): Hash function to use: * murmur3: MurmurHash3 hash function. * md5: MD5 hash function. + * sha1: SHA-1 hash function. + * sha224: SHA-224 hash function. + * sha256: SHA-256 hash function. + * sha384: SHA-384 hash function. + * sha512: SHA-512 hash function. Returns ------- diff --git a/python/cudf/cudf/core/series.py b/python/cudf/cudf/core/series.py index 73fdfed0524..f5753db323a 100644 --- a/python/cudf/cudf/core/series.py +++ b/python/cudf/cudf/core/series.py @@ -3609,6 +3609,11 @@ def hash_values(self, method="murmur3"): Hash function to use: * murmur3: MurmurHash3 hash function. * md5: MD5 hash function. + * sha1: SHA-1 hash function. + * sha224: SHA-224 hash function. + * sha256: SHA-256 hash function. + * sha384: SHA-384 hash function. + * sha512: SHA-512 hash function. Returns ------- From a373221ede4cfc5b0dff45d0c0cb960d4b373d90 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 18 Oct 2021 17:18:35 -0700 Subject: [PATCH 075/100] Add tests for SHA hashing. --- python/cudf/cudf/tests/test_dataframe.py | 5 +++- python/cudf/cudf/tests/test_series.py | 37 +++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/python/cudf/cudf/tests/test_dataframe.py b/python/cudf/cudf/tests/test_dataframe.py index efad96e9786..69f248403b2 100644 --- a/python/cudf/cudf/tests/test_dataframe.py +++ b/python/cudf/cudf/tests/test_dataframe.py @@ -1103,7 +1103,10 @@ def test_assign(): @pytest.mark.parametrize("nrows", [1, 8, 100, 1000]) -@pytest.mark.parametrize("method", ["murmur3", "md5"]) +@pytest.mark.parametrize( + "method", + ["murmur3", "md5", "sha1", "sha224", "sha256", "sha384", "sha512"], +) def test_dataframe_hash_columns(nrows, method): gdf = cudf.DataFrame() data = np.asarray(range(nrows)) diff --git a/python/cudf/cudf/tests/test_series.py b/python/cudf/cudf/tests/test_series.py index 7d62532776e..3e209426a18 100644 --- a/python/cudf/cudf/tests/test_series.py +++ b/python/cudf/cudf/tests/test_series.py @@ -1,5 +1,6 @@ # Copyright (c) 2020-2021, NVIDIA CORPORATION. +import hashlib import operator import re from string import ascii_letters, digits @@ -1275,26 +1276,9 @@ def test_series_sort_index( @pytest.mark.parametrize( - "method,validation_data", - [ - ( - "md5", - [ - "d41d8cd98f00b204e9800998ecf8427e", - "cfcd208495d565ef66e7dff9f98764da", - "3d3aaae21d57b101227f0384f644abe0", - "3e76c7023d771ad1c1520c27ab3d4874", - "f8d805e33ec3ade1a6ea251ac1c118e7", - "c30515f66a5aec7af7666abf33600c92", - "c61a4185135eda043f35e92c3505e180", - "52da74c75cb6575d25be29e66bd0adde", - "5152ac13bdd09110d9ee9c169a3d9237", - "f1d3ff8443297732862df21dc4e57262", - ], - ) - ], + "method", ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"] ) -def test_series_hash_values(method, validation_data): +def test_series_hash_values(method): inputs = cudf.Series( [ "", @@ -1313,6 +1297,19 @@ def test_series_hash_values(method, validation_data): "\x00\x00\x00\x00", ] ) - validation_results = cudf.Series(validation_data) + + def hashlib_compute_digest(data): + hasher = getattr(hashlib, method)() + hasher.update(data.encode("utf-8")) + return hasher.hexdigest() + + hashlib_validation = inputs.to_pandas().apply(hashlib_compute_digest) + validation_results = cudf.Series(hashlib_validation) hash_values = inputs.hash_values(method=method) assert_eq(hash_values, validation_results) + + +def test_series_hash_values_invalid_method(): + inputs = cudf.Series(["", "0"]) + with pytest.raises(ValueError): + inputs.hash_values(method="invalid_method") From a7773b83b9ea8d3e9037ba5b1eedb152d60f51b2 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 19 Oct 2021 17:44:39 -0700 Subject: [PATCH 076/100] Move result_location to constructor. --- cpp/src/hash/sha_hash.cu | 163 ++++++++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 38 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 039e53e63d7..f2cdedcdaba 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -37,6 +37,39 @@ namespace detail { namespace { +static const __device__ __constant__ uint32_t sha256_hash_constants[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +static const __device__ __constant__ uint64_t sha512_hash_constants[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; + // SHA supported leaf data type check bool sha_type_check(data_type dt) { @@ -78,7 +111,78 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) return (static_cast(low_bits) << 32) | (static_cast(high_bits)); }; -} // namespace +template +struct hash_circular_buffer { + uint8_t storage[capacity]; + uint8_t* cur; + hash_step_callable hash_step; + + CUDA_DEVICE_CALLABLE hash_circular_buffer(hash_step_callable hash_step) + : cur{storage}, hash_step{hash_step} + { + } + + CUDA_DEVICE_CALLABLE uint8_t* begin() { return storage; } + CUDA_DEVICE_CALLABLE const uint8_t* begin() const { return storage; } + + CUDA_DEVICE_CALLABLE int size() const + { + return std::distance(begin(), static_cast(cur)); + } + + CUDA_DEVICE_CALLABLE int available_space() const { return capacity - size(); } + + CUDA_DEVICE_CALLABLE void put(uint8_t const* in, int size) + { + int space = available_space(); + int copy_start = 0; + while (size >= space) { + // The buffer will be filled by this chunk of data. Copy a chunk of the + // data to fill the buffer and trigger a hash step. + memcpy(cur, in + copy_start, space); + hash_step(storage); + size -= space; + copy_start += space; + cur = begin(); + space = available_space(); + } + // The buffer will not be filled by the remaining data. That is, `size >= 0 + // && size < capacity`. We copy the remaining data into the buffer but do + // not trigger a hash step. + memcpy(cur, in + copy_start, size); + cur += size; + } + + CUDA_DEVICE_CALLABLE void pad(int space_to_leave) + { + int space = available_space(); + if (space_to_leave > space) { + memset(cur, 0x00, space); + hash_step(storage); + cur = begin(); + space = available_space(); + } + memset(cur, 0x00, space - space_to_leave); + cur += space - space_to_leave; + } + + CUDA_DEVICE_CALLABLE const uint8_t& operator[](int idx) const { return storage[idx]; } +}; + +template +auto CUDA_DEVICE_CALLABLE get_data(Key const& k) +{ + if constexpr (is_fixed_width() && !is_chrono()) { + return thrust::make_pair(reinterpret_cast(&k), sizeof(Key)); + } else { + cudf_assert(false && "Unsupported type."); + } +} + +auto CUDA_DEVICE_CALLABLE get_data(string_view const& k) +{ + return thrust::make_pair(reinterpret_cast(k.data()), k.size_bytes()); +} /** * @brief A CRTP helper function @@ -99,6 +203,10 @@ struct crtp { template struct HashBase : public crtp { + char* result_location; + + CUDA_DEVICE_CALLABLE HashBase(char* result_location) : result_location(result_location) {} + /** * @brief Execute SHA on input data chunks. * @@ -151,7 +259,7 @@ struct HashBase : public crtp { * the message length (in another step of the hash, if needed), and performs * the final hash step. */ - void CUDA_DEVICE_CALLABLE finalize(char* result_location) + void CUDA_DEVICE_CALLABLE finalize() { auto& state = this->underlying().state; // Message length in bits. @@ -317,39 +425,6 @@ struct sha512_hash_state { uint8_t buffer[128]; }; -__constant__ uint32_t sha256_hash_constants[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; - -__constant__ uint64_t sha512_hash_constants[80] = { - 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, - 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, - 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, - 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, - 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, - 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, - 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, - 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, - 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, - 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, - 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, - 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, - 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, - 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, - 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, - 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, - 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, -}; - /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -550,6 +625,8 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) } struct SHA1Hash : HashBase { + CUDA_DEVICE_CALLABLE SHA1Hash(char* result_location) : HashBase(result_location) {} + // Intermediate data type storing the hash state using hash_state = sha1_hash_state; // The word type used by this hash function @@ -567,6 +644,8 @@ struct SHA1Hash : HashBase { }; struct SHA224Hash : HashBase { + CUDA_DEVICE_CALLABLE SHA224Hash(char* result_location) : HashBase(result_location) {} + // Intermediate data type storing the hash state using hash_state = sha224_hash_state; // The word type used by this hash function @@ -584,6 +663,8 @@ struct SHA224Hash : HashBase { }; struct SHA256Hash : HashBase { + CUDA_DEVICE_CALLABLE SHA256Hash(char* result_location) : HashBase(result_location) {} + // Intermediate data type storing the hash state using hash_state = sha256_hash_state; // The word type used by this hash function @@ -601,6 +682,8 @@ struct SHA256Hash : HashBase { }; struct SHA384Hash : HashBase { + CUDA_DEVICE_CALLABLE SHA384Hash(char* result_location) : HashBase(result_location) {} + // Intermediate data type storing the hash state using hash_state = sha384_hash_state; // The word type used by this hash function @@ -618,6 +701,8 @@ struct SHA384Hash : HashBase { }; struct SHA512Hash : HashBase { + CUDA_DEVICE_CALLABLE SHA512Hash(char* result_location) : HashBase(result_location) {} + // Intermediate data type storing the hash state using hash_state = sha512_hash_state; // The word type used by this hash function @@ -634,6 +719,8 @@ struct SHA512Hash : HashBase { hash_state state; }; +} // namespace + /** * @brief Call a SHA-1 or SHA-2 hash function on a table view. * @@ -685,7 +772,8 @@ std::unique_ptr sha_hash(table_view const& input, thrust::make_counting_iterator(0), thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { - Hasher hasher = Hasher{}; + auto const result_location = d_chars + (row_index * Hasher::digest_size); + Hasher hasher = Hasher{result_location}; for (auto const& col : device_input) { if (col.is_valid(row_index)) { HasherDispatcher hasher_dispatcher{&hasher, col}; @@ -693,8 +781,7 @@ std::unique_ptr sha_hash(table_view const& input, col.type(), hasher_dispatcher, row_index); } } - auto const result_location = d_chars + (row_index * Hasher::digest_size); - hasher.finalize(result_location); + hasher.finalize(); }); return make_strings_column( From 927b4194db137609a0546d3ff90b1f103140f077 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 12:44:21 -0700 Subject: [PATCH 077/100] Fix SHA constant qualifiers. --- cpp/src/hash/sha_hash.cu | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index f2cdedcdaba..29ed47582ec 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -37,7 +37,7 @@ namespace detail { namespace { -static const __device__ __constant__ uint32_t sha256_hash_constants[64] = { +const __constant__ uint32_t sha256_hash_constants[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, @@ -45,9 +45,10 @@ static const __device__ __constant__ uint32_t sha256_hash_constants[64] = { 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; -static const __device__ __constant__ uint64_t sha512_hash_constants[80] = { +const __constant__ uint64_t sha512_hash_constants[80] = { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, From 6decb54209fec2ccecedd484f61e8fc12ad4aecb Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 12:44:37 -0700 Subject: [PATCH 078/100] Rename and move leaf type check. --- cpp/src/hash/sha_hash.cu | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 29ed47582ec..38557e5b81c 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -71,12 +71,6 @@ const __constant__ uint64_t sha512_hash_constants[80] = { 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -// SHA supported leaf data type check -bool sha_type_check(data_type dt) -{ - return !is_chrono(dt) && (is_fixed_width(dt) || (dt.id() == type_id::STRING)); -} - CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) { // This function is equivalent to (x << r) | (x >> (32 - r)) @@ -720,6 +714,12 @@ struct SHA512Hash : HashBase { hash_state state; }; +// SHA supported leaf data type check +constexpr inline bool sha_leaf_type_check(data_type dt) +{ + return (is_fixed_width(dt) && !is_chrono(dt)) || (dt.id() == type_id::STRING); +} + } // namespace /** @@ -750,7 +750,7 @@ std::unique_ptr sha_hash(table_view const& input, // TODO: Accept single layer list columns holding those types. CUDF_EXPECTS( std::all_of( - input.begin(), input.end(), [](auto const& col) { return sha_type_check(col.type()); }), + input.begin(), input.end(), [](auto const& col) { return sha_leaf_type_check(col.type()); }), "Unsupported column type for hash function."); // Result column allocation and creation From 95b0945b1578223b0cd529daebb5a81b491a464f Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 12:54:18 -0700 Subject: [PATCH 079/100] Move shared utility functions to utilities/hash_functions.cuh. --- .../cudf/detail/utilities/hash_functions.cuh | 35 +++++++++++++++++++ cpp/src/hash/sha_hash.cu | 35 ------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index ebb21492be9..86b30e74340 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -43,6 +43,41 @@ T CUDA_DEVICE_CALLABLE normalize_nans_and_zeros(T const& key) return key; } +CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) +{ + // This function is equivalent to (x << r) | (x >> (32 - r)) + return __funnelshift_l(x, x, r); +} + +CUDA_DEVICE_CALLABLE uint32_t rotate_bits_right(uint32_t x, int8_t r) +{ + // This function is equivalent to (x >> r) | (x << (32 - r)) + return __funnelshift_r(x, x, r); +} + +CUDA_DEVICE_CALLABLE uint64_t rotate_bits_right(uint64_t x, int8_t r) +{ + return (x >> r) | (x << (64 - r)); +} + +// Swap the endianness of a 32 bit value +CUDA_DEVICE_CALLABLE uint32_t swap_endian(uint32_t x) +{ + // The selector 0x0123 reverses the byte order + return __byte_perm(x, 0, 0x0123); +} + +// Swap the endianness of a 64 bit value +// There is no CUDA intrinsic for permuting bytes in 64 bit integers +CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) +{ + // Reverse the endianness of each 32 bit section + uint32_t low_bits = swap_endian(static_cast(x)); + uint32_t high_bits = swap_endian(static_cast(x >> 32)); + // Reassemble a 64 bit result, swapping the low bits and high bits + return (static_cast(low_bits) << 32) | (static_cast(high_bits)); +}; + /** * Modified GPU implementation of * https://johnnylee-sde.github.io/Fast-unsigned-integer-to-hex-string/ diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 38557e5b81c..44d11461aba 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -71,41 +71,6 @@ const __constant__ uint64_t sha512_hash_constants[80] = { 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -CUDA_DEVICE_CALLABLE uint32_t rotate_bits_left(uint32_t x, int8_t r) -{ - // This function is equivalent to (x << r) | (x >> (32 - r)) - return __funnelshift_l(x, x, r); -} - -CUDA_DEVICE_CALLABLE uint32_t rotate_bits_right(uint32_t x, int8_t r) -{ - // This function is equivalent to (x >> r) | (x << (32 - r)) - return __funnelshift_r(x, x, r); -} - -CUDA_DEVICE_CALLABLE uint64_t rotate_bits_right(uint64_t x, int8_t r) -{ - return (x >> r) | (x << (64 - r)); -} - -// Swap the endianness of a 32 bit value -CUDA_DEVICE_CALLABLE uint32_t swap_endian(uint32_t x) -{ - // The selector 0x0123 reverses the byte order - return __byte_perm(x, 0, 0x0123); -} - -// Swap the endianness of a 64 bit value -// There is no CUDA intrinsic for permuting bytes in 64 bit integers -CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) -{ - // Reverse the endianness of each 32 bit section - uint32_t low_bits = swap_endian(static_cast(x)); - uint32_t high_bits = swap_endian(static_cast(x >> 32)); - // Reassemble a 64 bit result, swapping the low bits and high bits - return (static_cast(low_bits) << 32) | (static_cast(high_bits)); -}; - template struct hash_circular_buffer { uint8_t storage[capacity]; From 327effb05480a64359e42d64d8e1c077f5042235 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 12:54:39 -0700 Subject: [PATCH 080/100] Clean up use of utility functions. --- .../cudf/detail/utilities/hash_functions.cuh | 66 +++++++++++++++++ cpp/src/hash/md5_hash.cu | 68 +---------------- cpp/src/hash/sha_hash.cu | 73 ------------------- 3 files changed, 67 insertions(+), 140 deletions(-) diff --git a/cpp/include/cudf/detail/utilities/hash_functions.cuh b/cpp/include/cudf/detail/utilities/hash_functions.cuh index 86b30e74340..79908a96781 100644 --- a/cpp/include/cudf/detail/utilities/hash_functions.cuh +++ b/cpp/include/cudf/detail/utilities/hash_functions.cuh @@ -78,6 +78,72 @@ CUDA_DEVICE_CALLABLE uint64_t swap_endian(uint64_t x) return (static_cast(low_bits) << 32) | (static_cast(high_bits)); }; +template +struct hash_circular_buffer { + uint8_t storage[capacity]; + uint8_t* cur; + int available_space{capacity}; + hash_step_callable hash_step; + + CUDA_DEVICE_CALLABLE hash_circular_buffer(hash_step_callable hash_step) + : cur{storage}, hash_step{hash_step} + { + } + + CUDA_DEVICE_CALLABLE void put(uint8_t const* in, int size) + { + int copy_start = 0; + while (size >= available_space) { + // The buffer will be filled by this chunk of data. Copy a chunk of the + // data to fill the buffer and trigger a hash step. + memcpy(cur, in + copy_start, available_space); + hash_step(storage); + size -= available_space; + copy_start += available_space; + cur = storage; + available_space = capacity; + } + // The buffer will not be filled by the remaining data. That is, `size >= 0 + // && size < capacity`. We copy the remaining data into the buffer but do + // not trigger a hash step. + memcpy(cur, in + copy_start, size); + cur += size; + available_space -= size; + } + + CUDA_DEVICE_CALLABLE void pad(int const space_to_leave) + { + if (space_to_leave > available_space) { + memset(cur, 0x00, available_space); + hash_step(storage); + cur = storage; + available_space = capacity; + } + memset(cur, 0x00, available_space - space_to_leave); + cur += available_space - space_to_leave; + available_space = space_to_leave; + } + + CUDA_DEVICE_CALLABLE const uint8_t& operator[](int idx) const { return storage[idx]; } +}; + +// Get a uint8_t pointer to a column element and its size as a pair. +template +auto CUDA_DEVICE_CALLABLE get_element_pointer_and_size(Element const& element) +{ + if constexpr (is_fixed_width() && !is_chrono()) { + return thrust::make_pair(reinterpret_cast(&element), sizeof(Element)); + } else { + cudf_assert(false && "Unsupported type."); + } +} + +template <> +auto CUDA_DEVICE_CALLABLE get_element_pointer_and_size(string_view const& element) +{ + return thrust::make_pair(reinterpret_cast(element.data()), element.size_bytes()); +} + /** * Modified GPU implementation of * https://johnnylee-sde.github.io/Fast-unsigned-integer-to-hex-string/ diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index d0e47d93bc6..6ded51d9dc3 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -55,72 +55,6 @@ const __constant__ uint32_t md5_hash_constants[64] = { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; -template -struct hash_circular_buffer { - uint8_t storage[capacity]; - uint8_t* cur; - int available_space{capacity}; - hash_step_callable hash_step; - - CUDA_DEVICE_CALLABLE hash_circular_buffer(hash_step_callable hash_step) - : cur{storage}, hash_step{hash_step} - { - } - - CUDA_DEVICE_CALLABLE void put(uint8_t const* in, int size) - { - int copy_start = 0; - while (size >= available_space) { - // The buffer will be filled by this chunk of data. Copy a chunk of the - // data to fill the buffer and trigger a hash step. - memcpy(cur, in + copy_start, available_space); - hash_step(storage); - size -= available_space; - copy_start += available_space; - cur = storage; - available_space = capacity; - } - // The buffer will not be filled by the remaining data. That is, `size >= 0 - // && size < capacity`. We copy the remaining data into the buffer but do - // not trigger a hash step. - memcpy(cur, in + copy_start, size); - cur += size; - available_space -= size; - } - - CUDA_DEVICE_CALLABLE void pad(int const space_to_leave) - { - if (space_to_leave > available_space) { - memset(cur, 0x00, available_space); - hash_step(storage); - cur = storage; - available_space = capacity; - } - memset(cur, 0x00, available_space - space_to_leave); - cur += available_space - space_to_leave; - available_space = space_to_leave; - } - - CUDA_DEVICE_CALLABLE const uint8_t& operator[](int idx) const { return storage[idx]; } -}; - -// Get a uint8_t pointer to a column element and its size as a pair. -template -auto CUDA_DEVICE_CALLABLE get_element_pointer_and_size(Element const& element) -{ - if constexpr (is_fixed_width() && !is_chrono()) { - return thrust::make_pair(reinterpret_cast(&element), sizeof(Element)); - } else { - cudf_assert(false && "Unsupported type."); - } -} - -template <> -auto CUDA_DEVICE_CALLABLE get_element_pointer_and_size(string_view const& element) -{ - return thrust::make_pair(reinterpret_cast(element.data()), element.size_bytes()); -} - struct MD5Hasher { static constexpr int message_chunk_size = 64; @@ -205,7 +139,7 @@ struct MD5Hasher { A = D; D = C; C = B; - B = B + __funnelshift_l(F, F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); + B = B + rotate_bits_left(F, md5_shift_constants[((j / 16) * 4) + (j % 4)]); } hash_values[0] += A; diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 44d11461aba..a1b34c2b088 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -71,79 +71,6 @@ const __constant__ uint64_t sha512_hash_constants[80] = { 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, }; -template -struct hash_circular_buffer { - uint8_t storage[capacity]; - uint8_t* cur; - hash_step_callable hash_step; - - CUDA_DEVICE_CALLABLE hash_circular_buffer(hash_step_callable hash_step) - : cur{storage}, hash_step{hash_step} - { - } - - CUDA_DEVICE_CALLABLE uint8_t* begin() { return storage; } - CUDA_DEVICE_CALLABLE const uint8_t* begin() const { return storage; } - - CUDA_DEVICE_CALLABLE int size() const - { - return std::distance(begin(), static_cast(cur)); - } - - CUDA_DEVICE_CALLABLE int available_space() const { return capacity - size(); } - - CUDA_DEVICE_CALLABLE void put(uint8_t const* in, int size) - { - int space = available_space(); - int copy_start = 0; - while (size >= space) { - // The buffer will be filled by this chunk of data. Copy a chunk of the - // data to fill the buffer and trigger a hash step. - memcpy(cur, in + copy_start, space); - hash_step(storage); - size -= space; - copy_start += space; - cur = begin(); - space = available_space(); - } - // The buffer will not be filled by the remaining data. That is, `size >= 0 - // && size < capacity`. We copy the remaining data into the buffer but do - // not trigger a hash step. - memcpy(cur, in + copy_start, size); - cur += size; - } - - CUDA_DEVICE_CALLABLE void pad(int space_to_leave) - { - int space = available_space(); - if (space_to_leave > space) { - memset(cur, 0x00, space); - hash_step(storage); - cur = begin(); - space = available_space(); - } - memset(cur, 0x00, space - space_to_leave); - cur += space - space_to_leave; - } - - CUDA_DEVICE_CALLABLE const uint8_t& operator[](int idx) const { return storage[idx]; } -}; - -template -auto CUDA_DEVICE_CALLABLE get_data(Key const& k) -{ - if constexpr (is_fixed_width() && !is_chrono()) { - return thrust::make_pair(reinterpret_cast(&k), sizeof(Key)); - } else { - cudf_assert(false && "Unsupported type."); - } -} - -auto CUDA_DEVICE_CALLABLE get_data(string_view const& k) -{ - return thrust::make_pair(reinterpret_cast(k.data()), k.size_bytes()); -} - /** * @brief A CRTP helper function * From f2f6715adf74f48ef97f93dee34a85fa86a70520 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 18:20:44 -0700 Subject: [PATCH 081/100] Add includes for column_device_view. --- cpp/src/hash/md5_hash.cu | 1 + cpp/src/hash/sha_hash.cu | 1 + 2 files changed, 2 insertions(+) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 6ded51d9dc3..c4a1f97a161 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include #include diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index a1b34c2b088..c9c187da6e8 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include #include From 665a69231ea352f7d90e9ecd356a1932fff10071 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 18:21:09 -0700 Subject: [PATCH 082/100] Simplify dispatcher construction. --- cpp/src/hash/sha_hash.cu | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c9c187da6e8..1a2b146332d 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -223,7 +223,12 @@ struct HashBase : public crtp { template struct HasherDispatcher { Hasher* hasher; - column_device_view col; + column_device_view input_col; + + CUDA_DEVICE_CALLABLE HasherDispatcher(Hasher* hasher, column_device_view const& input_col) + : hasher{hasher}, input_col{input_col} + { + } template () || is_chrono()) && @@ -237,7 +242,7 @@ struct HasherDispatcher { typename std::enable_if_t() && !is_chrono()>* = nullptr> void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { - T const& key = col.element(row_index); + T const& key = input_col.element(row_index); if constexpr (is_floating_point()) { if (isnan(key)) { T nan = std::numeric_limits::quiet_NaN(); @@ -255,7 +260,7 @@ struct HasherDispatcher { template >* = nullptr> void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { - string_view key = col.element(row_index); + string_view key = input_col.element(row_index); uint8_t const* data = reinterpret_cast(key.data()); uint32_t const len = static_cast(key.size_bytes()); hasher->process(data, len); @@ -666,13 +671,11 @@ std::unique_ptr sha_hash(table_view const& input, thrust::make_counting_iterator(0), thrust::make_counting_iterator(input.num_rows()), [d_chars, device_input = *device_input] __device__(auto row_index) { - auto const result_location = d_chars + (row_index * Hasher::digest_size); - Hasher hasher = Hasher{result_location}; + Hasher hasher(d_chars + (row_index * Hasher::digest_size)); for (auto const& col : device_input) { if (col.is_valid(row_index)) { - HasherDispatcher hasher_dispatcher{&hasher, col}; cudf::type_dispatcher( - col.type(), hasher_dispatcher, row_index); + col.type(), HasherDispatcher(&hasher, col), row_index); } } hasher.finalize(); From bce1f655228763765ac4fc43400e37f05ec6d44e Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 19:15:20 -0700 Subject: [PATCH 083/100] Combine SFINAE templates into one method with if constexpr. --- cpp/src/hash/sha_hash.cu | 46 +++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 1a2b146332d..d6772dcae8b 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -230,41 +230,33 @@ struct HasherDispatcher { { } - template () || is_chrono()) && - !std::is_same_v>* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(size_type) - { - cudf_assert(false && "Unsupported type for hash function."); - } - - template () && !is_chrono()>* = nullptr> + template void CUDA_DEVICE_CALLABLE operator()(size_type row_index) { - T const& key = input_col.element(row_index); - if constexpr (is_floating_point()) { - if (isnan(key)) { - T nan = std::numeric_limits::quiet_NaN(); - hasher->process_fixed_width(nan); - } else if (key == T{0.0}) { - hasher->process_fixed_width(T{0.0}); + if constexpr (is_fixed_width() && !is_chrono()) { + Element const& key = input_col.element(row_index); + if constexpr (is_floating_point()) { + if (isnan(key)) { + Element nan = std::numeric_limits::quiet_NaN(); + hasher->process_fixed_width(nan); + } else if (key == Element{0.0}) { + hasher->process_fixed_width(Element{0.0}); + } else { + hasher->process_fixed_width(key); + } } else { hasher->process_fixed_width(key); } + } else if constexpr (std::is_same_v) { + string_view key = input_col.element(row_index); + uint8_t const* data = reinterpret_cast(key.data()); + uint32_t const len = static_cast(key.size_bytes()); + hasher->process(data, len); } else { - hasher->process_fixed_width(key); + (void)row_index; + cudf_assert(false && "Unsupported type for hash function."); } } - - template >* = nullptr> - void CUDA_DEVICE_CALLABLE operator()(size_type row_index) - { - string_view key = input_col.element(row_index); - uint8_t const* data = reinterpret_cast(key.data()); - uint32_t const len = static_cast(key.size_bytes()); - hasher->process(data, len); - } }; struct sha1_hash_state { From aa1426196227e28bd4d5e0d78adfc77ac206bc4c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 19:32:14 -0700 Subject: [PATCH 084/100] Use bitmask_and for MD5 null mask. --- cpp/src/hash/md5_hash.cu | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index c4a1f97a161..28ebde4a853 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -244,7 +245,8 @@ std::unique_ptr md5_hash(table_view const& input, auto chars_view = chars_column->mutable_view(); auto d_chars = chars_view.data(); - rmm::device_buffer null_mask{0, stream, mr}; + // Build an output null mask from the logical AND of all input columns' null masks. + rmm::device_buffer null_mask{cudf::detail::bitmask_and(input, stream)}; auto const device_input = table_device_view::create(input, stream); From adf2a23a142469489dca3d07da199e9b734e6e9d Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Mon, 25 Oct 2021 19:33:23 -0700 Subject: [PATCH 085/100] Move base sha_hash function into anonymous namespace. --- cpp/src/hash/sha_hash.cu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index d6772dcae8b..c189698852e 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -610,8 +610,6 @@ constexpr inline bool sha_leaf_type_check(data_type dt) return (is_fixed_width(dt) && !is_chrono(dt)) || (dt.id() == type_id::STRING); } -} // namespace - /** * @brief Call a SHA-1 or SHA-2 hash function on a table view. * @@ -677,6 +675,8 @@ std::unique_ptr sha_hash(table_view const& input, input.num_rows(), std::move(offsets_column), std::move(chars_column), 0, std::move(null_mask)); } +} // namespace + std::unique_ptr sha1_hash(table_view const& input, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) From c6f6a8220449dbcd52e18b2d0f5d9fcfb68116f1 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 25 Jun 2022 03:51:08 -0500 Subject: [PATCH 086/100] Update copyright. --- cpp/src/hash/sha_hash.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c189698852e..c518197ac8e 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. + * Copyright (c) 2019-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 96cd76fe8462c3bcf529c69b925db0eee39eee7b Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 16 Nov 2022 23:11:40 -0600 Subject: [PATCH 087/100] Use __device__ inline instead of CUDA_DEVICE_CALLABLE. --- cpp/src/hash/sha_hash.cu | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index c518197ac8e..842a2450d56 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -85,15 +85,15 @@ const __constant__ uint64_t sha512_hash_constants[80] = { */ template struct crtp { - CUDA_DEVICE_CALLABLE T& underlying() { return static_cast(*this); } - CUDA_DEVICE_CALLABLE T const& underlying() const { return static_cast(*this); } + __device__ inline T& underlying() { return static_cast(*this); } + __device__ inline T const& underlying() const { return static_cast(*this); } }; template struct HashBase : public crtp { char* result_location; - CUDA_DEVICE_CALLABLE HashBase(char* result_location) : result_location(result_location) {} + __device__ inline HashBase(char* result_location) : result_location(result_location) {} /** * @brief Execute SHA on input data chunks. @@ -101,7 +101,7 @@ struct HashBase : public crtp { * This accepts arbitrary data, handles it as bytes, and calls the hash step * when the buffer is filled up to message_chunk_size bytes. */ - void CUDA_DEVICE_CALLABLE process(uint8_t const* data, uint32_t len) + void __device__ inline process(uint8_t const* data, uint32_t len) { auto& state = this->underlying().state; state.message_length += len; @@ -133,7 +133,7 @@ struct HashBase : public crtp { } template - void CUDA_DEVICE_CALLABLE process_fixed_width(T const& key) + void __device__ inline process_fixed_width(T const& key) { uint8_t const* data = reinterpret_cast(&key); uint32_t constexpr len = sizeof(T); @@ -147,7 +147,7 @@ struct HashBase : public crtp { * the message length (in another step of the hash, if needed), and performs * the final hash step. */ - void CUDA_DEVICE_CALLABLE finalize() + void __device__ inline finalize() { auto& state = this->underlying().state; // Message length in bits. @@ -225,13 +225,13 @@ struct HasherDispatcher { Hasher* hasher; column_device_view input_col; - CUDA_DEVICE_CALLABLE HasherDispatcher(Hasher* hasher, column_device_view const& input_col) + __device__ inline HasherDispatcher(Hasher* hasher, column_device_view const& input_col) : hasher{hasher}, input_col{input_col} { } template - void CUDA_DEVICE_CALLABLE operator()(size_type row_index) + void __device__ inline operator()(size_type row_index) { if constexpr (is_fixed_width() && !is_chrono()) { Element const& key = input_col.element(row_index); @@ -315,7 +315,7 @@ struct sha512_hash_state { * updating the hash value so far. Does not zero out the buffer contents. */ template -void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) +void __device__ inline sha1_hash_step(hash_state& state) { uint32_t words[80]; @@ -382,7 +382,7 @@ void CUDA_DEVICE_CALLABLE sha1_hash_step(hash_state& state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) +void __device__ inline sha256_hash_step(hash_state& state) { uint32_t words[64]; @@ -448,7 +448,7 @@ void CUDA_DEVICE_CALLABLE sha256_hash_step(hash_state& state) * updating the hash value so far. Does not zero out the buffer contents. */ template -void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) +void __device__ inline sha512_hash_step(hash_state& state) { uint64_t words[80]; @@ -510,7 +510,7 @@ void CUDA_DEVICE_CALLABLE sha512_hash_step(hash_state& state) } struct SHA1Hash : HashBase { - CUDA_DEVICE_CALLABLE SHA1Hash(char* result_location) : HashBase(result_location) {} + __device__ inline SHA1Hash(char* result_location) : HashBase(result_location) {} // Intermediate data type storing the hash state using hash_state = sha1_hash_state; @@ -523,13 +523,13 @@ struct SHA1Hash : HashBase { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha1_hash_step(state); } + void __device__ inline hash_step(hash_state& state) { sha1_hash_step(state); } hash_state state; }; struct SHA224Hash : HashBase { - CUDA_DEVICE_CALLABLE SHA224Hash(char* result_location) : HashBase(result_location) {} + __device__ inline SHA224Hash(char* result_location) : HashBase(result_location) {} // Intermediate data type storing the hash state using hash_state = sha224_hash_state; @@ -542,13 +542,13 @@ struct SHA224Hash : HashBase { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha256_hash_step(state); } + void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } hash_state state; }; struct SHA256Hash : HashBase { - CUDA_DEVICE_CALLABLE SHA256Hash(char* result_location) : HashBase(result_location) {} + __device__ inline SHA256Hash(char* result_location) : HashBase(result_location) {} // Intermediate data type storing the hash state using hash_state = sha256_hash_state; @@ -561,13 +561,13 @@ struct SHA256Hash : HashBase { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 8; - void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha256_hash_step(state); } + void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } hash_state state; }; struct SHA384Hash : HashBase { - CUDA_DEVICE_CALLABLE SHA384Hash(char* result_location) : HashBase(result_location) {} + __device__ inline SHA384Hash(char* result_location) : HashBase(result_location) {} // Intermediate data type storing the hash state using hash_state = sha384_hash_state; @@ -580,13 +580,13 @@ struct SHA384Hash : HashBase { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 16; - void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha512_hash_step(state); } + void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } hash_state state; }; struct SHA512Hash : HashBase { - CUDA_DEVICE_CALLABLE SHA512Hash(char* result_location) : HashBase(result_location) {} + __device__ inline SHA512Hash(char* result_location) : HashBase(result_location) {} // Intermediate data type storing the hash state using hash_state = sha512_hash_state; @@ -599,7 +599,7 @@ struct SHA512Hash : HashBase { // Number of bytes used for the message length static constexpr uint32_t message_length_size = 16; - void CUDA_DEVICE_CALLABLE hash_step(hash_state& state) { sha512_hash_step(state); } + void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } hash_state state; }; From 3b2b6184e941ca73317d63bd8507fbc1c2babe61 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 16 Nov 2022 23:20:07 -0600 Subject: [PATCH 088/100] Use null count from bitmask_and. --- cpp/src/hash/sha_hash.cu | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 842a2450d56..03f41b44211 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -652,7 +652,7 @@ std::unique_ptr sha_hash(table_view const& input, auto d_chars = chars_view.template data(); // Build an output null mask from the logical AND of all input columns' null masks. - rmm::device_buffer null_mask{cudf::detail::bitmask_and(input, stream)}; + auto [null_mask, null_count] = cudf::detail::bitmask_and(input, stream); auto const device_input = table_device_view::create(input, stream); @@ -671,8 +671,11 @@ std::unique_ptr sha_hash(table_view const& input, hasher.finalize(); }); - return make_strings_column( - input.num_rows(), std::move(offsets_column), std::move(chars_column), 0, std::move(null_mask)); + return make_strings_column(input.num_rows(), + std::move(offsets_column), + std::move(chars_column), + null_count, + std::move(null_mask)); } } // namespace From 706c7028f2aaee0df74e9d5c91a3de416a3c2d1b Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 10:27:01 -0600 Subject: [PATCH 089/100] Drop constexpr because is_fixed_width is no longer constexpr. --- cpp/src/hash/sha_hash.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 03f41b44211..407f90b593c 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -605,7 +605,7 @@ struct SHA512Hash : HashBase { }; // SHA supported leaf data type check -constexpr inline bool sha_leaf_type_check(data_type dt) +bool sha_leaf_type_check(data_type dt) { return (is_fixed_width(dt) && !is_chrono(dt)) || (dt.id() == type_id::STRING); } From 9e44661dc3a2b4ffafab28598e0ce4bed3a48b2c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 10:27:21 -0600 Subject: [PATCH 090/100] Use CUDF_TEST_EXPECT_COLUMNS_EQUAL. --- cpp/tests/hashing/hash_test.cpp | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 68740a6d12f..0f6bf9f84d8 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -1238,7 +1238,7 @@ TEST_F(SHA1HashTest, MultiValueNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1257,7 +1257,7 @@ TYPED_TEST(SHA1HashTestTyped, Equality) auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); EXPECT_EQ(input.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } TYPED_TEST(SHA1HashTestTyped, EqualityNulls) @@ -1275,7 +1275,7 @@ TYPED_TEST(SHA1HashTestTyped, EqualityNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1302,7 +1302,7 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } class SHA224HashTest : public cudf::test::BaseFixture { @@ -1417,7 +1417,7 @@ TEST_F(SHA224HashTest, MultiValueNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1436,7 +1436,7 @@ TYPED_TEST(SHA224HashTestTyped, Equality) auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA224); EXPECT_EQ(input.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } TYPED_TEST(SHA224HashTestTyped, EqualityNulls) @@ -1454,7 +1454,7 @@ TYPED_TEST(SHA224HashTestTyped, EqualityNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1481,7 +1481,7 @@ TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } class SHA256HashTest : public cudf::test::BaseFixture { @@ -1596,7 +1596,7 @@ TEST_F(SHA256HashTest, MultiValueNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1615,7 +1615,7 @@ TYPED_TEST(SHA256HashTestTyped, Equality) auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA256); EXPECT_EQ(input.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } TYPED_TEST(SHA256HashTestTyped, EqualityNulls) @@ -1633,7 +1633,7 @@ TYPED_TEST(SHA256HashTestTyped, EqualityNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1660,7 +1660,7 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } class SHA384HashTest : public cudf::test::BaseFixture { @@ -1791,7 +1791,7 @@ TEST_F(SHA384HashTest, MultiValueNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1810,7 +1810,7 @@ TYPED_TEST(SHA384HashTestTyped, Equality) auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA384); EXPECT_EQ(input.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } TYPED_TEST(SHA384HashTestTyped, EqualityNulls) @@ -1828,7 +1828,7 @@ TYPED_TEST(SHA384HashTestTyped, EqualityNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -1855,7 +1855,7 @@ TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } class SHA512HashTest : public cudf::test::BaseFixture { @@ -1986,7 +1986,7 @@ TEST_F(SHA512HashTest, MultiValueNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -2005,7 +2005,7 @@ TYPED_TEST(SHA512HashTestTyped, Equality) auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA512); EXPECT_EQ(input.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } TYPED_TEST(SHA512HashTestTyped, EqualityNulls) @@ -2023,7 +2023,7 @@ TYPED_TEST(SHA512HashTestTyped, EqualityNulls) auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); EXPECT_EQ(input1.num_rows(), output1->size()); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } template @@ -2050,7 +2050,7 @@ TYPED_TEST(SHA512HashTestFloatTyped, TestExtremes) auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); - expect_columns_equal(output1->view(), output2->view()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } CUDF_TEST_PROGRAM_MAIN() From 17591c77fd5ec12947f858dd5f821c483b11291f Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 12:57:55 -0600 Subject: [PATCH 091/100] Fix namespaces. --- cpp/tests/hashing/hash_test.cpp | 282 +++++++++++++++++--------------- 1 file changed, 147 insertions(+), 135 deletions(-) diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index 0f6bf9f84d8..a59041c0680 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -1147,7 +1147,7 @@ TEST_F(SHA1HashTest, EmptyTable) TEST_F(SHA1HashTest, MultiValue) { - strings_column_wrapper const strings_col( + cudf::test::strings_column_wrapper const strings_col( {"", "0", "A 56 character string to test message padding algorithm.", @@ -1158,31 +1158,33 @@ TEST_F(SHA1HashTest, MultiValue) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - strings_column_wrapper const sha1_string_results1({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "b6589fc6ab0dc82cf12099d1c2d40ab994e8410c", - "cb73203438ab46ea54491c53e288a2703c440c4a", - "c595ebd13a785c1c2659e010a42e2ff9987ef51f", - "4ffaf61804c55b8c2171be548bef2e1d0baca17a", - "595965dd18f38087186162c788485fe249242131", - "a62ca720fbab830c8890044eacbeac216f1ca2e4", - "11e16c52273b5669a41d17ec7c187475193f88b3"}); - - strings_column_wrapper const sha1_string_results2({"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "fb96549631c835eb239cd614cc6b5cb7d295121a", - "e3977ee0ea7f238134ec93c79988fa84b7c5d79e", - "f6f75b6fa3c3d8d86b44fcb2c98c9ad4b37dcdd0", - "c7abd431a775c604edf41a62f7f215e7258dc16a", - "153fdf20d2bd8ae76241197314d6e0be7fe10f50", - "8c3656f7cb37898f9296c1965000d6da13fed64e", - "b4a848399375ec842c2cb445d98b5f80a4dce94f"}); + cudf::test::strings_column_wrapper const sha1_string_results1( + {"da39a3ee5e6b4b0d3255bfef95601890afd80709", + "b6589fc6ab0dc82cf12099d1c2d40ab994e8410c", + "cb73203438ab46ea54491c53e288a2703c440c4a", + "c595ebd13a785c1c2659e010a42e2ff9987ef51f", + "4ffaf61804c55b8c2171be548bef2e1d0baca17a", + "595965dd18f38087186162c788485fe249242131", + "a62ca720fbab830c8890044eacbeac216f1ca2e4", + "11e16c52273b5669a41d17ec7c187475193f88b3"}); + + cudf::test::strings_column_wrapper const sha1_string_results2( + {"da39a3ee5e6b4b0d3255bfef95601890afd80709", + "fb96549631c835eb239cd614cc6b5cb7d295121a", + "e3977ee0ea7f238134ec93c79988fa84b7c5d79e", + "f6f75b6fa3c3d8d86b44fcb2c98c9ad4b37dcdd0", + "c7abd431a775c604edf41a62f7f215e7258dc16a", + "153fdf20d2bd8ae76241197314d6e0be7fe10f50", + "8c3656f7cb37898f9296c1965000d6da13fed64e", + "b4a848399375ec842c2cb445d98b5f80a4dce94f"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col( + cudf::test::fixed_width_column_wrapper const ints_col( {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); @@ -1204,7 +1206,7 @@ TEST_F(SHA1HashTest, MultiValue) TEST_F(SHA1HashTest, MultiValueNulls) { // Nulls with different values should be equal - strings_column_wrapper const strings_col1( + cudf::test::strings_column_wrapper const strings_col1( {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " @@ -1212,24 +1214,25 @@ TEST_F(SHA1HashTest, MultiValueNulls) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); - strings_column_wrapper const strings_col2({"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); + cudf::test::strings_column_wrapper const strings_col2( + {"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 0}); - fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const ints_col1( + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const ints_col2( + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1249,7 +1252,7 @@ TYPED_TEST_CASE(SHA1HashTestTyped, cudf::test::NumericTypes); TYPED_TEST(SHA1HashTestTyped, Equality) { - fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); auto const input = cudf::table_view({col}); // Hash of same input should be equal @@ -1265,8 +1268,8 @@ TYPED_TEST(SHA1HashTestTyped, EqualityNulls) using T = TypeParam; // Nulls with different values should be equal - fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); @@ -1292,8 +1295,9 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) T nan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); - fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - fixed_width_column_wrapper const col2( + cudf::test::fixed_width_column_wrapper const col1( + {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + cudf::test::fixed_width_column_wrapper const col2( {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); auto const input1 = cudf::table_view({col1}); @@ -1324,7 +1328,7 @@ TEST_F(SHA224HashTest, EmptyTable) TEST_F(SHA224HashTest, MultiValue) { - strings_column_wrapper const strings_col( + cudf::test::strings_column_wrapper const strings_col( {"", "0", "A 56 character string to test message padding algorithm.", @@ -1335,7 +1339,7 @@ TEST_F(SHA224HashTest, MultiValue) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - strings_column_wrapper const sha224_string_results1( + cudf::test::strings_column_wrapper const sha224_string_results1( {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "dfd5f9139a820075df69d7895015360b76d0360f3d4b77a845689614", "5d1ed8373987e403482cefe1662a63fa3076c0a5331d141f41654bbe", @@ -1345,7 +1349,7 @@ TEST_F(SHA224HashTest, MultiValue) "e7d0adb165079efc6c6343112f8b154aa3644ca6326f658aaa0f8e4a", "309cc09eaa051beea7d0b0159daca9b4e8a533cb554e8f382c82709e"}); - strings_column_wrapper const sha224_string_results2( + cudf::test::strings_column_wrapper const sha224_string_results2( {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "5538ae2b02d4ae0b7090dc908ca69cd11a2ffad43c7435f1dbad5e6a", "8e1955a473a149368dc0a931f99379b44b0bb752f206dbdf68629232", @@ -1356,12 +1360,12 @@ TEST_F(SHA224HashTest, MultiValue) "d219eefea538491efcb69bc5bbef4177ad991d1b6e1367b5981b8c31"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col( + cudf::test::fixed_width_column_wrapper const ints_col( {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); @@ -1383,7 +1387,7 @@ TEST_F(SHA224HashTest, MultiValue) TEST_F(SHA224HashTest, MultiValueNulls) { // Nulls with different values should be equal - strings_column_wrapper const strings_col1( + cudf::test::strings_column_wrapper const strings_col1( {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " @@ -1391,24 +1395,25 @@ TEST_F(SHA224HashTest, MultiValueNulls) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); - strings_column_wrapper const strings_col2({"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); + cudf::test::strings_column_wrapper const strings_col2( + {"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 0}); - fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const ints_col1( + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const ints_col2( + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1428,7 +1433,7 @@ TYPED_TEST_CASE(SHA224HashTestTyped, cudf::test::NumericTypes); TYPED_TEST(SHA224HashTestTyped, Equality) { - fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); auto const input = cudf::table_view({col}); // Hash of same input should be equal @@ -1444,8 +1449,8 @@ TYPED_TEST(SHA224HashTestTyped, EqualityNulls) using T = TypeParam; // Nulls with different values should be equal - fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); @@ -1471,8 +1476,9 @@ TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) T nan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); - fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - fixed_width_column_wrapper const col2( + cudf::test::fixed_width_column_wrapper const col1( + {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + cudf::test::fixed_width_column_wrapper const col2( {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); auto const input1 = cudf::table_view({col1}); @@ -1503,7 +1509,7 @@ TEST_F(SHA256HashTest, EmptyTable) TEST_F(SHA256HashTest, MultiValue) { - strings_column_wrapper const strings_col( + cudf::test::strings_column_wrapper const strings_col( {"", "0", "A 56 character string to test message padding algorithm.", @@ -1514,7 +1520,7 @@ TEST_F(SHA256HashTest, MultiValue) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - strings_column_wrapper const sha256_string_results1( + cudf::test::strings_column_wrapper const sha256_string_results1( {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9", "d16883c666112142c1d72c9080b41161be7563250539e3f6ab6e2fdf2210074b", @@ -1524,7 +1530,7 @@ TEST_F(SHA256HashTest, MultiValue) "2ce9936a4a2234bf8a76c37d92e01d549d03949792242e7f8a1ad68575e4e4a8", "255fdd4d80a72f67921eb36f3e1157ea3e995068cee80e430c034e0d3692f614"}); - strings_column_wrapper const sha256_string_results2( + cudf::test::strings_column_wrapper const sha256_string_results2( {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "f1534392279bddbf9d43dde8701cb5be14b82f76ec6607bf8d6ad557f60f304e", "96c204fa5d44b2487abfec105a05f8ae634551604f6596202ca99e3724e3953a", @@ -1535,12 +1541,12 @@ TEST_F(SHA256HashTest, MultiValue) "4ddc45855d7ce3ab09efacff1fbafb33502f7dd468dc5a62826689c1c658dbce"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col( + cudf::test::fixed_width_column_wrapper const ints_col( {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); @@ -1562,7 +1568,7 @@ TEST_F(SHA256HashTest, MultiValue) TEST_F(SHA256HashTest, MultiValueNulls) { // Nulls with different values should be equal - strings_column_wrapper const strings_col1( + cudf::test::strings_column_wrapper const strings_col1( {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " @@ -1570,24 +1576,25 @@ TEST_F(SHA256HashTest, MultiValueNulls) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); - strings_column_wrapper const strings_col2({"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); + cudf::test::strings_column_wrapper const strings_col2( + {"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 0}); - fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const ints_col1( + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const ints_col2( + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1607,7 +1614,7 @@ TYPED_TEST_CASE(SHA256HashTestTyped, cudf::test::NumericTypes); TYPED_TEST(SHA256HashTestTyped, Equality) { - fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); auto const input = cudf::table_view({col}); // Hash of same input should be equal @@ -1623,8 +1630,8 @@ TYPED_TEST(SHA256HashTestTyped, EqualityNulls) using T = TypeParam; // Nulls with different values should be equal - fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); @@ -1650,8 +1657,9 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) T nan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); - fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - fixed_width_column_wrapper const col2( + cudf::test::fixed_width_column_wrapper const col1( + {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + cudf::test::fixed_width_column_wrapper const col2( {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); auto const input1 = cudf::table_view({col1}); @@ -1682,7 +1690,7 @@ TEST_F(SHA384HashTest, EmptyTable) TEST_F(SHA384HashTest, MultiValue) { - strings_column_wrapper const strings_col( + cudf::test::strings_column_wrapper const strings_col( {"", "0", "A 56 character string to test message padding algorithm.", @@ -1693,7 +1701,7 @@ TEST_F(SHA384HashTest, MultiValue) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - strings_column_wrapper const sha384_string_results1( + cudf::test::strings_column_wrapper const sha384_string_results1( {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" "95b", "5f91550edb03f0bb8917da57f0f8818976f5da971307b7ee4886bb951c4891a1f16f840dae8f655aa5df718884ebc" @@ -1711,7 +1719,7 @@ TEST_F(SHA384HashTest, MultiValue) "3a9d1a870a5f6a4c04df1daf1808163d33852897ebc757a5b028a1214fbc758485a392159b11bc360cfadc79f9512" "822"}); - strings_column_wrapper const sha384_string_results2( + cudf::test::strings_column_wrapper const sha384_string_results2( {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" "95b", "34ae2cd40efabf896d8d4173e500278d10671b2d914efb5480e8349190bc7e8e1d532ad568d00a8295ea536a9b42b" @@ -1730,12 +1738,12 @@ TEST_F(SHA384HashTest, MultiValue) "edf"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col( + cudf::test::fixed_width_column_wrapper const ints_col( {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); @@ -1757,7 +1765,7 @@ TEST_F(SHA384HashTest, MultiValue) TEST_F(SHA384HashTest, MultiValueNulls) { // Nulls with different values should be equal - strings_column_wrapper const strings_col1( + cudf::test::strings_column_wrapper const strings_col1( {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " @@ -1765,24 +1773,25 @@ TEST_F(SHA384HashTest, MultiValueNulls) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); - strings_column_wrapper const strings_col2({"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); + cudf::test::strings_column_wrapper const strings_col2( + {"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 0}); - fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const ints_col1( + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const ints_col2( + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1802,7 +1811,7 @@ TYPED_TEST_CASE(SHA384HashTestTyped, cudf::test::NumericTypes); TYPED_TEST(SHA384HashTestTyped, Equality) { - fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); auto const input = cudf::table_view({col}); // Hash of same input should be equal @@ -1818,8 +1827,8 @@ TYPED_TEST(SHA384HashTestTyped, EqualityNulls) using T = TypeParam; // Nulls with different values should be equal - fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); @@ -1845,8 +1854,9 @@ TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) T nan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); - fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - fixed_width_column_wrapper const col2( + cudf::test::fixed_width_column_wrapper const col1( + {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + cudf::test::fixed_width_column_wrapper const col2( {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); auto const input1 = cudf::table_view({col1}); @@ -1877,7 +1887,7 @@ TEST_F(SHA512HashTest, EmptyTable) TEST_F(SHA512HashTest, MultiValue) { - strings_column_wrapper const strings_col( + cudf::test::strings_column_wrapper const strings_col( {"", "0", "A 56 character string to test message padding algorithm.", @@ -1888,7 +1898,7 @@ TEST_F(SHA512HashTest, MultiValue) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - strings_column_wrapper const sha512_string_results1( + cudf::test::strings_column_wrapper const sha512_string_results1( {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" "c2f63b931bd47417a81a538327af927da3e", "31bca02094eb78126a517b206a88c73cfa9ec6f704c7030d18212cace820f025f00bf0ea68dbf3f3a5436ca63b53b" @@ -1906,7 +1916,7 @@ TEST_F(SHA512HashTest, MultiValue) "05a4ca1c523dcab32edb7d8793934a4cdf41a9062b229d711f5326e297bda83fa965118b9d7636172b43688e8e149" "008b3f967f1a969962b7e959af894a8a315"}); - strings_column_wrapper const sha512_string_results2( + cudf::test::strings_column_wrapper const sha512_string_results2( {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" "c2f63b931bd47417a81a538327af927da3e", "8ab3361c051a97ddc3c665d29f2762f8ac4240d08995f8724b6d07d8cbedd32c28f589ccdae514f20a6c8eea6f755" @@ -1925,12 +1935,12 @@ TEST_F(SHA512HashTest, MultiValue) "d1eebe0661386909684927d67819a2cf736"}); using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col( + cudf::test::fixed_width_column_wrapper const ints_col( {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); // Different truth values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); @@ -1952,7 +1962,7 @@ TEST_F(SHA512HashTest, MultiValue) TEST_F(SHA512HashTest, MultiValueNulls) { // Nulls with different values should be equal - strings_column_wrapper const strings_col1( + cudf::test::strings_column_wrapper const strings_col1( {"", "Different but null!", "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " @@ -1960,24 +1970,25 @@ TEST_F(SHA512HashTest, MultiValueNulls) "All work and no play makes Jack a dull boy", "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, {1, 0, 0, 1, 0}); - strings_column_wrapper const strings_col2({"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); + cudf::test::strings_column_wrapper const strings_col2( + {"", + "Another string that is null.", + "Very different... but null", + "All work and no play makes Jack a dull boy", + ""}, + {1, 0, 0, 1, 0}); // Nulls with different values should be equal using limits = std::numeric_limits; - fixed_width_column_wrapper const ints_col1({0, 100, -100, limits::min(), limits::max()}, - {1, 0, 0, 1, 0}); - fixed_width_column_wrapper const ints_col2({0, -200, 200, limits::min(), limits::max()}, - {1, 0, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const ints_col1( + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const ints_col2( + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); // Nulls with different values should be equal // Different truthy values should be equal - fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); @@ -1997,7 +2008,7 @@ TYPED_TEST_CASE(SHA512HashTestTyped, cudf::test::NumericTypes); TYPED_TEST(SHA512HashTestTyped, Equality) { - fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); + cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); auto const input = cudf::table_view({col}); // Hash of same input should be equal @@ -2013,8 +2024,8 @@ TYPED_TEST(SHA512HashTestTyped, EqualityNulls) using T = TypeParam; // Nulls with different values should be equal - fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); + cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); @@ -2040,8 +2051,9 @@ TYPED_TEST(SHA512HashTestFloatTyped, TestExtremes) T nan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); - fixed_width_column_wrapper const col1({T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - fixed_width_column_wrapper const col2( + cudf::test::fixed_width_column_wrapper const col1( + {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); + cudf::test::fixed_width_column_wrapper const col2( {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); auto const input1 = cudf::table_view({col1}); From 00b172c223babc78a38659321cf9fbf5262d089c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 13:11:32 -0600 Subject: [PATCH 092/100] Remove default stream/mr. --- cpp/include/cudf/detail/hashing.hpp | 42 +++++++++++++---------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/cpp/include/cudf/detail/hashing.hpp b/cpp/include/cudf/detail/hashing.hpp index 5d9739374ac..bf75189b9aa 100644 --- a/cpp/include/cudf/detail/hashing.hpp +++ b/cpp/include/cudf/detail/hashing.hpp @@ -50,35 +50,29 @@ std::unique_ptr spark_murmur_hash3_32( rmm::cuda_stream_view stream = cudf::get_default_stream(), rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); -std::unique_ptr md5_hash( - table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr md5_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); -std::unique_ptr sha1_hash( - table_view const& input, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha1_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); -std::unique_ptr sha224_hash( - table_view const& input, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha224_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); -std::unique_ptr sha256_hash( - table_view const& input, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha256_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); -std::unique_ptr sha384_hash( - table_view const& input, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha384_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); -std::unique_ptr sha512_hash( - table_view const& input, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); +std::unique_ptr sha512_hash(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr); /* Copyright 2005-2014 Daniel James. * From 9689d923b7c94a9b499a33def4c9fe0064921fe2 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 13:29:54 -0600 Subject: [PATCH 093/100] Update includes. --- cpp/src/hash/sha_hash.cu | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index 407f90b593c..b06b88122d3 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, NVIDIA CORPORATION. + * Copyright (c) 2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,12 +26,17 @@ #include #include +#include #include #include #include +#include #include +#include +#include #include +#include namespace cudf { namespace detail { From 1dba6b318c6aa972c76e96478763fa0831dbbe70 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 17 Nov 2022 16:56:05 -0600 Subject: [PATCH 094/100] Try compiling sha_hash.cu in CI without debug flag. --- cpp/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 9d0937b9ad3..a54f2a42950 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -596,8 +596,6 @@ set_target_properties( INTERFACE_POSITION_INDEPENDENT_CODE ON ) -set_source_files_properties(src/hash/sha_hash.cu PROPERTIES COMPILE_OPTIONS "-G") - target_compile_options( cudf PRIVATE "$<$:${CUDF_CXX_FLAGS}>" "$<$:${CUDF_CUDA_FLAGS}>" From dfa1dbbd81837eb7da8ee4c7bab91e28cf836b31 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 1 Feb 2023 11:41:15 -0600 Subject: [PATCH 095/100] Update copyright. --- cpp/benchmarks/hashing/hash.cpp | 2 +- cpp/include/cudf/detail/hashing.hpp | 2 +- cpp/include/cudf/hashing.hpp | 2 +- cpp/src/hash/hashing.cu | 2 +- cpp/src/hash/sha_hash.cu | 2 +- cpp/tests/hashing/hash_test.cpp | 2 +- python/cudf/cudf/_lib/cpp/hash.pxd | 2 +- python/cudf/cudf/_lib/hash.pyx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cpp/benchmarks/hashing/hash.cpp b/cpp/benchmarks/hashing/hash.cpp index a622761d8e8..da198ba62c0 100644 --- a/cpp/benchmarks/hashing/hash.cpp +++ b/cpp/benchmarks/hashing/hash.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022, NVIDIA CORPORATION. + * Copyright (c) 2021-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/include/cudf/detail/hashing.hpp b/cpp/include/cudf/detail/hashing.hpp index bf75189b9aa..5a5486e79e2 100644 --- a/cpp/include/cudf/detail/hashing.hpp +++ b/cpp/include/cudf/detail/hashing.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, NVIDIA CORPORATION. + * Copyright (c) 2019-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/include/cudf/hashing.hpp b/cpp/include/cudf/hashing.hpp index 3cef4b85b49..fcb0c41e724 100644 --- a/cpp/include/cudf/hashing.hpp +++ b/cpp/include/cudf/hashing.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, NVIDIA CORPORATION. + * Copyright (c) 2019-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/src/hash/hashing.cu b/cpp/src/hash/hashing.cu index a09dccac04f..412637055cc 100644 --- a/cpp/src/hash/hashing.cu +++ b/cpp/src/hash/hashing.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, NVIDIA CORPORATION. + * Copyright (c) 2019-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cu index b06b88122d3..2f07ec5b73d 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cu @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, NVIDIA CORPORATION. + * Copyright (c) 2022-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/tests/hashing/hash_test.cpp b/cpp/tests/hashing/hash_test.cpp index a59041c0680..0b0e61ca000 100644 --- a/cpp/tests/hashing/hash_test.cpp +++ b/cpp/tests/hashing/hash_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022, NVIDIA CORPORATION. + * Copyright (c) 2019-2023, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/python/cudf/cudf/_lib/cpp/hash.pxd b/python/cudf/cudf/_lib/cpp/hash.pxd index b5c8958587f..c5e435aceb7 100644 --- a/python/cudf/cudf/_lib/cpp/hash.pxd +++ b/python/cudf/cudf/_lib/cpp/hash.pxd @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2022, NVIDIA CORPORATION. +# Copyright (c) 2020-2023, NVIDIA CORPORATION. from libc.stdint cimport uint32_t from libcpp.memory cimport unique_ptr diff --git a/python/cudf/cudf/_lib/hash.pyx b/python/cudf/cudf/_lib/hash.pyx index cfb2a49db5e..8bdbed6c2b1 100644 --- a/python/cudf/cudf/_lib/hash.pyx +++ b/python/cudf/cudf/_lib/hash.pyx @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2022, NVIDIA CORPORATION. +# Copyright (c) 2020-2023, NVIDIA CORPORATION. from cudf.core.buffer import acquire_spill_lock From 143ae6a2cd4e82e23d1a94a701b3821d449a10ad Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 17 Oct 2023 15:48:58 -0700 Subject: [PATCH 096/100] Remove combined test file. --- cpp/tests/hashing/sha_test.cpp | 948 --------------------------------- 1 file changed, 948 deletions(-) delete mode 100644 cpp/tests/hashing/sha_test.cpp diff --git a/cpp/tests/hashing/sha_test.cpp b/cpp/tests/hashing/sha_test.cpp deleted file mode 100644 index 950543d9503..00000000000 --- a/cpp/tests/hashing/sha_test.cpp +++ /dev/null @@ -1,948 +0,0 @@ -/* - * Copyright (c) 2019-2023, NVIDIA CORPORATION. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include -#include -#include -#include - -constexpr cudf::test::debug_output_level verbosity{cudf::test::debug_output_level::ALL_ERRORS}; - -class SHA1HashTest : public cudf::test::BaseFixture {}; - -TEST_F(SHA1HashTest, EmptyTable) -{ - auto const empty_table = cudf::table_view{}; - auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); - EXPECT_EQ(empty_column->size(), output_empty_table->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); - - auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); - EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); -} - -TEST_F(SHA1HashTest, MultiValue) -{ - cudf::test::strings_column_wrapper const strings_col( - {"", - "0", - "A 56 character string to test message padding algorithm.", - "A 63 character string to test message padding algorithm, again.", - "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - - cudf::test::strings_column_wrapper const sha1_string_results1( - {"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "b6589fc6ab0dc82cf12099d1c2d40ab994e8410c", - "cb73203438ab46ea54491c53e288a2703c440c4a", - "c595ebd13a785c1c2659e010a42e2ff9987ef51f", - "4ffaf61804c55b8c2171be548bef2e1d0baca17a", - "595965dd18f38087186162c788485fe249242131", - "a62ca720fbab830c8890044eacbeac216f1ca2e4", - "11e16c52273b5669a41d17ec7c187475193f88b3"}); - - cudf::test::strings_column_wrapper const sha1_string_results2( - {"da39a3ee5e6b4b0d3255bfef95601890afd80709", - "fb96549631c835eb239cd614cc6b5cb7d295121a", - "e3977ee0ea7f238134ec93c79988fa84b7c5d79e", - "f6f75b6fa3c3d8d86b44fcb2c98c9ad4b37dcdd0", - "c7abd431a775c604edf41a62f7f215e7258dc16a", - "153fdf20d2bd8ae76241197314d6e0be7fe10f50", - "8c3656f7cb37898f9296c1965000d6da13fed64e", - "b4a848399375ec842c2cb445d98b5f80a4dce94f"}); - - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col( - {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); - - // Different truth values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); - - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha1_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA1); - auto const sha1_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA1); - EXPECT_EQ(string_input1.num_rows(), sha1_string_output1->size()); - EXPECT_EQ(string_input2.num_rows(), sha1_string_output2->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output1->view(), sha1_string_results1); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output2->view(), sha1_string_results2); - - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha1_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const sha1_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - EXPECT_EQ(input1.num_rows(), sha1_output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_output1->view(), sha1_output2->view()); -} - -TEST_F(SHA1HashTest, MultiValueNulls) -{ - // Nulls with different values should be equal - cudf::test::strings_column_wrapper const strings_col1( - {"", - "Different but null!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, - {1, 0, 0, 1, 0}); - cudf::test::strings_column_wrapper const strings_col2( - {"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); - - // Nulls with different values should be equal - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); - cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); - - // Nulls with different values should be equal - // Different truthy values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); - - auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); - auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA1HashTestTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA1HashTestTyped, cudf::test::NumericTypes); - -TYPED_TEST(SHA1HashTestTyped, Equality) -{ - cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); - auto const input = cudf::table_view({col}); - - // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); - - EXPECT_EQ(input.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -TYPED_TEST(SHA1HashTestTyped, EqualityNulls) -{ - using T = TypeParam; - - // Nulls with different values should be equal - cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA1HashTestFloatTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA1HashTestFloatTyped, cudf::test::FloatingPointTypes); - -TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) -{ - using T = TypeParam; - T min = std::numeric_limits::min(); - T max = std::numeric_limits::max(); - T nan = std::numeric_limits::quiet_NaN(); - T inf = std::numeric_limits::infinity(); - - cudf::test::fixed_width_column_wrapper const col1( - {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - cudf::test::fixed_width_column_wrapper const col2( - {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); - - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -class SHA224HashTest : public cudf::test::BaseFixture {}; - -TEST_F(SHA224HashTest, EmptyTable) -{ - auto const empty_table = cudf::table_view{}; - auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); - EXPECT_EQ(empty_column->size(), output_empty_table->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); - - auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); - EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); -} - -TEST_F(SHA224HashTest, MultiValue) -{ - cudf::test::strings_column_wrapper const strings_col( - {"", - "0", - "A 56 character string to test message padding algorithm.", - "A 63 character string to test message padding algorithm, again.", - "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - - cudf::test::strings_column_wrapper const sha224_string_results1( - {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", - "dfd5f9139a820075df69d7895015360b76d0360f3d4b77a845689614", - "5d1ed8373987e403482cefe1662a63fa3076c0a5331d141f41654bbe", - "0662c91000b99de7a20c89097dd62f59120398d52499497489ccff95", - "f9ea303770699483f3e53263b32a3b3c876d1b8808ce84df4b8ca1c4", - "2da6cd4bdaa0a99fd7236cd5507c52e12328e71192e83b32d2f110f9", - "e7d0adb165079efc6c6343112f8b154aa3644ca6326f658aaa0f8e4a", - "309cc09eaa051beea7d0b0159daca9b4e8a533cb554e8f382c82709e"}); - - cudf::test::strings_column_wrapper const sha224_string_results2( - {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", - "5538ae2b02d4ae0b7090dc908ca69cd11a2ffad43c7435f1dbad5e6a", - "8e1955a473a149368dc0a931f99379b44b0bb752f206dbdf68629232", - "8581001e08295b7884428c022378cfdd643c977aefe4512f0252dc30", - "d5854dfe3c32996345b103a6a16c7bdfa924723d620b150737e77370", - "dd56deac5f2caa579a440ee814fc04a3afaf805d567087ac3317beb3", - "14fb559f6309604bedd89183f585f3b433932b5b0e675848feebf8ec", - "d219eefea538491efcb69bc5bbef4177ad991d1b6e1367b5981b8c31"}); - - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col( - {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); - - // Different truth values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); - - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha224_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA224); - auto const sha224_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA224); - EXPECT_EQ(string_input1.num_rows(), sha224_string_output1->size()); - EXPECT_EQ(string_input2.num_rows(), sha224_string_output2->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_string_output1->view(), sha224_string_results1); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_string_output2->view(), sha224_string_results2); - - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha224_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const sha224_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); - EXPECT_EQ(input1.num_rows(), sha224_output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_output1->view(), sha224_output2->view()); -} - -TEST_F(SHA224HashTest, MultiValueNulls) -{ - // Nulls with different values should be equal - cudf::test::strings_column_wrapper const strings_col1( - {"", - "Different but null!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, - {1, 0, 0, 1, 0}); - cudf::test::strings_column_wrapper const strings_col2( - {"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); - - // Nulls with different values should be equal - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); - cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); - - // Nulls with different values should be equal - // Different truthy values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); - - auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); - auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA224HashTestTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA224HashTestTyped, cudf::test::NumericTypes); - -TYPED_TEST(SHA224HashTestTyped, Equality) -{ - cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); - auto const input = cudf::table_view({col}); - - // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA224); - - EXPECT_EQ(input.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -TYPED_TEST(SHA224HashTestTyped, EqualityNulls) -{ - using T = TypeParam; - - // Nulls with different values should be equal - cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA224HashTestFloatTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA224HashTestFloatTyped, cudf::test::FloatingPointTypes); - -TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) -{ - using T = TypeParam; - T min = std::numeric_limits::min(); - T max = std::numeric_limits::max(); - T nan = std::numeric_limits::quiet_NaN(); - T inf = std::numeric_limits::infinity(); - - cudf::test::fixed_width_column_wrapper const col1( - {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - cudf::test::fixed_width_column_wrapper const col2( - {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); - - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -class SHA256HashTest : public cudf::test::BaseFixture {}; - -TEST_F(SHA256HashTest, EmptyTable) -{ - auto const empty_table = cudf::table_view{}; - auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); - EXPECT_EQ(empty_column->size(), output_empty_table->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); - - auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); - EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); -} - -TEST_F(SHA256HashTest, MultiValue) -{ - cudf::test::strings_column_wrapper const strings_col( - {"", - "0", - "A 56 character string to test message padding algorithm.", - "A 63 character string to test message padding algorithm, again.", - "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - - cudf::test::strings_column_wrapper const sha256_string_results1( - {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9", - "d16883c666112142c1d72c9080b41161be7563250539e3f6ab6e2fdf2210074b", - "11174fa180460f5d683c2e63fcdd897dcbf10c28a9225d3ced9a8bbc3774415d", - "10a7d211e692c6f71bb9f7524ba1437588c2797356f05fc585340f002fe7015e", - "339d610dcb030bb4222bcf18c8ab82d911bfe7fb95b2cd9f6785fd4562b02401", - "2ce9936a4a2234bf8a76c37d92e01d549d03949792242e7f8a1ad68575e4e4a8", - "255fdd4d80a72f67921eb36f3e1157ea3e995068cee80e430c034e0d3692f614"}); - - cudf::test::strings_column_wrapper const sha256_string_results2( - {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "f1534392279bddbf9d43dde8701cb5be14b82f76ec6607bf8d6ad557f60f304e", - "96c204fa5d44b2487abfec105a05f8ae634551604f6596202ca99e3724e3953a", - "2e7be264f3ecbb2930e7c54bf6c5fc1f310a8c63c50916bb713f34699ed11719", - "224e4dce71d5dbd5e79ba65aaced7ad9c4f45dda146278087b2b61d164f056f0", - "91f3108d4e9c696fdb37ae49fdc6a2237f1d1f977b7216406cc8a6365355f43b", - "490be480afe271685e9c1fdf46daac0b9bf7f25602e153ca92a0ddb0e4b662ef", - "4ddc45855d7ce3ab09efacff1fbafb33502f7dd468dc5a62826689c1c658dbce"}); - - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col( - {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); - - // Different truth values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); - - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha256_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA256); - auto const sha256_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA256); - EXPECT_EQ(string_input1.num_rows(), sha256_string_output1->size()); - EXPECT_EQ(string_input2.num_rows(), sha256_string_output2->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_string_output1->view(), sha256_string_results1); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_string_output2->view(), sha256_string_results2); - - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha256_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const sha256_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); - EXPECT_EQ(input1.num_rows(), sha256_output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_output1->view(), sha256_output2->view()); -} - -TEST_F(SHA256HashTest, MultiValueNulls) -{ - // Nulls with different values should be equal - cudf::test::strings_column_wrapper const strings_col1( - {"", - "Different but null!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, - {1, 0, 0, 1, 0}); - cudf::test::strings_column_wrapper const strings_col2( - {"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); - - // Nulls with different values should be equal - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); - cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); - - // Nulls with different values should be equal - // Different truthy values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); - - auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); - auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA256HashTestTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA256HashTestTyped, cudf::test::NumericTypes); - -TYPED_TEST(SHA256HashTestTyped, Equality) -{ - cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); - auto const input = cudf::table_view({col}); - - // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA256); - - EXPECT_EQ(input.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -TYPED_TEST(SHA256HashTestTyped, EqualityNulls) -{ - using T = TypeParam; - - // Nulls with different values should be equal - cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA256HashTestFloatTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA256HashTestFloatTyped, cudf::test::FloatingPointTypes); - -TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) -{ - using T = TypeParam; - T min = std::numeric_limits::min(); - T max = std::numeric_limits::max(); - T nan = std::numeric_limits::quiet_NaN(); - T inf = std::numeric_limits::infinity(); - - cudf::test::fixed_width_column_wrapper const col1( - {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - cudf::test::fixed_width_column_wrapper const col2( - {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); - - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -class SHA384HashTest : public cudf::test::BaseFixture {}; - -TEST_F(SHA384HashTest, EmptyTable) -{ - auto const empty_table = cudf::table_view{}; - auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); - EXPECT_EQ(empty_column->size(), output_empty_table->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); - - auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); - EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); -} - -TEST_F(SHA384HashTest, MultiValue) -{ - cudf::test::strings_column_wrapper const strings_col( - {"", - "0", - "A 56 character string to test message padding algorithm.", - "A 63 character string to test message padding algorithm, again.", - "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - - cudf::test::strings_column_wrapper const sha384_string_results1( - {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" - "95b", - "5f91550edb03f0bb8917da57f0f8818976f5da971307b7ee4886bb951c4891a1f16f840dae8f655aa5df718884ebc" - "15b", - "982000cce895dc439edbcb7ba5b908cb5b7e939fe913d58506a486735a914b0dfbcebb02c33c428287baa0bfc7fe0" - "948", - "c3ea54e4d6d97c2a84dac9ac48ed9dd1a49118be880d8466044720cfdcd23427bf556f12204bb34ede29dbf207033" - "78c", - "5d7a853a18138fa90feac07c896dfca65a0f1eb2ed40f1fd7be6238dd7ef429bb1aeb0236735500eb954c9b4ba923" - "254", - "c72bcaf3a4b01986711cd5d2614aa8f9d7fad61455613eac4561b1468f9a25dd26566c8ad1190dec7567be4f6fc1d" - "b29", - "281826f23bebb3f835d2f15edcb0cdb3078ae2d7dc516f3a366af172dff4db6dd5833bc1e5ee411d52c598773e939" - "7b6", - "3a9d1a870a5f6a4c04df1daf1808163d33852897ebc757a5b028a1214fbc758485a392159b11bc360cfadc79f9512" - "822"}); - - cudf::test::strings_column_wrapper const sha384_string_results2( - {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b" - "95b", - "34ae2cd40efabf896d8d4173e500278d10671b2d914efb5480e8349190bc7e8e1d532ad568d00a8295ea536a9b42b" - "bc6", - "e80c25efd8032ea94dad1509a68f9bf745ce1184b8a148714c28c7e0fae1100ab14057417394f83118eaa151e014d" - "917", - "69eaddc4ef2ed967fc6a86d3ed3777b2c2015df4cf8bbbf65681556f451a4a0ae805a89c2d56641b4422b5f248c56" - "77d", - "112a6f9c74741d490747db90f5e901a88b7a32f637c030d6d96e5f89a70a5f1ee209e018648842c0e1d32002f95fd" - "d07", - "dc6f24bb0eb2c96fb53c52c402f073de089f3aeae9594be0c4f4cb31b13bd48769b80aa97d83a25ece1edf0c83373" - "f56", - "781a33adfdcdcbb514318728c074fbb59d44002995825642e0c9bfef8a2ccf3fb637b39ff3dd265df8cd93c86e945" - "ce9", - "d2efb1591c4503f23c34ddb4da6bb1017d3d4d7c9f23ee6aa52e71c98d41060bc35eb22f41b6130d5c42a6e717fb3" - "edf"}); - - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col( - {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); - - // Different truth values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); - - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha384_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA384); - auto const sha384_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA384); - EXPECT_EQ(string_input1.num_rows(), sha384_string_output1->size()); - EXPECT_EQ(string_input2.num_rows(), sha384_string_output2->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_string_output1->view(), sha384_string_results1, verbosity); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_string_output2->view(), sha384_string_results2, verbosity); - - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha384_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const sha384_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); - EXPECT_EQ(input1.num_rows(), sha384_output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_output1->view(), sha384_output2->view(), verbosity); -} - -TEST_F(SHA384HashTest, MultiValueNulls) -{ - // Nulls with different values should be equal - cudf::test::strings_column_wrapper const strings_col1( - {"", - "Different but null!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, - {1, 0, 0, 1, 0}); - cudf::test::strings_column_wrapper const strings_col2( - {"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); - - // Nulls with different values should be equal - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); - cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); - - // Nulls with different values should be equal - // Different truthy values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); - - auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); - auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA384HashTestTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA384HashTestTyped, cudf::test::NumericTypes); - -TYPED_TEST(SHA384HashTestTyped, Equality) -{ - cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); - auto const input = cudf::table_view({col}); - - // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA384); - - EXPECT_EQ(input.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -TYPED_TEST(SHA384HashTestTyped, EqualityNulls) -{ - using T = TypeParam; - - // Nulls with different values should be equal - cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA384HashTestFloatTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA384HashTestFloatTyped, cudf::test::FloatingPointTypes); - -TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) -{ - using T = TypeParam; - T min = std::numeric_limits::min(); - T max = std::numeric_limits::max(); - T nan = std::numeric_limits::quiet_NaN(); - T inf = std::numeric_limits::infinity(); - - cudf::test::fixed_width_column_wrapper const col1( - {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - cudf::test::fixed_width_column_wrapper const col2( - {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); - - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -class SHA512HashTest : public cudf::test::BaseFixture {}; - -TEST_F(SHA512HashTest, EmptyTable) -{ - auto const empty_table = cudf::table_view{}; - auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); - EXPECT_EQ(empty_column->size(), output_empty_table->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); - - auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); - EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); -} - -TEST_F(SHA512HashTest, MultiValue) -{ - cudf::test::strings_column_wrapper const strings_col( - {"", - "0", - "A 56 character string to test message padding algorithm.", - "A 63 character string to test message padding algorithm, again.", - "A 64 character string to test message padding algorithm, again!!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}); - - cudf::test::strings_column_wrapper const sha512_string_results1( - {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" - "c2f63b931bd47417a81a538327af927da3e", - "31bca02094eb78126a517b206a88c73cfa9ec6f704c7030d18212cace820f025f00bf0ea68dbf3f3a5436ca63b53b" - "f7bf80ad8d5de7d8359d0b7fed9dbc3ab99", - "1d8b355dbe0c4ad81c9815a1490f0b6a6fa710e42ca60767ffd6d845acd116defe307c9496a80c4a67653873af6ed" - "83e2e04c2102f55f9cd402677b246832e4c", - "8ac8ae9de5597aa630f071f81fcb94dc93b6a8f92d8f2cdd5a469764a5daf6ef387b6465ae097dcd6e0c64286260d" - "cc3d2c789d2cf5960df648c78a765e6c27c", - "9c436e24be60e17425a1a829642d97e7180b57485cf95db007cf5b32bbae1f2325b6874b3377e37806b15b739bffa" - "412ea6d095b726487d70e7b50e92d56c750", - "6a25ca1f20f6e79faea2a0770075e4262beb66b40f59c22d3e8abdb6188ef8d8914faf5dbf6df76165bb61b81dfda" - "46643f0d6366a39f7bd3d270312f9d3cf87", - "bae9eb4b5c05a4c5f85750b70b2f0ce78e387f992f0927a017eb40bd180a13004f6252a6bbf9816f195fb7d86668c" - "393dc0985aaf7168f48e8b905f3b9b02df2", - "05a4ca1c523dcab32edb7d8793934a4cdf41a9062b229d711f5326e297bda83fa965118b9d7636172b43688e8e149" - "008b3f967f1a969962b7e959af894a8a315"}); - - cudf::test::strings_column_wrapper const sha512_string_results2( - {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877ee" - "c2f63b931bd47417a81a538327af927da3e", - "8ab3361c051a97ddc3c665d29f2762f8ac4240d08995f8724b6d07d8cbedd32c28f589ccdae514f20a6c8eea6f755" - "408dd3dd6837d66932ca2352eaeab594427", - "338b22eb841420affff9904f903ed14c91bf8f4d1b10f25c145a31018367607a2cf562121ba7eaa2d08db3382cc82" - "149805198c1fa3e7dc714fc2782e0f6ebd8", - "d3045ecde16ea036d2f2ff3fa685beb46d5fcb73de71f0aee653265f18b22e4c131255e6eb5ad3be2f32914408ec6" - "67911b49d951714decbdbfca1957be8ba10", - "da7706221f8861ef522ab9555f57306382fb18c337536545d839e431dede4ff9f9affafb82ab5588734a8fc6631e6" - "a0cd864634b62e24a42755c863c5d5c5848", - "04dadc8fdf205fe535c8eb38f20882fc2a0e308081052d7588e74f6620aa207749039468c126db7407050def80415" - "1d037cb188d5d4d459015032972a9e9f001", - "aae2e742074847889a029a8d3170f9e17177d48ec0b9dabe572aa68dd3001af0c512f164ba84aa75b13950948170a" - "0912912d16c98d2f05cb633c0d5b6a9105e", - "77f46e99a7a51ac04b4380ebca70c0782381629f711169a3b9dad3fc9aa6221a9c0cdaa9b9ea4329773e773e2987c" - "d1eebe0661386909684927d67819a2cf736"}); - - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col( - {0, 100, -100, limits::min(), limits::max(), 1, 2, 3}); - - // Different truth values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 1, 1, 0, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 1, 2, 255, 0, 1, 2, 255}); - - auto const string_input1 = cudf::table_view({strings_col}); - auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha512_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA512); - auto const sha512_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA512); - EXPECT_EQ(string_input1.num_rows(), sha512_string_output1->size()); - EXPECT_EQ(string_input2.num_rows(), sha512_string_output2->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_string_output1->view(), sha512_string_results1, verbosity); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_string_output2->view(), sha512_string_results2, verbosity); - - auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); - auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha512_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const sha512_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); - EXPECT_EQ(input1.num_rows(), sha512_output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_output1->view(), sha512_output2->view(), verbosity); -} - -TEST_F(SHA512HashTest, MultiValueNulls) -{ - // Nulls with different values should be equal - cudf::test::strings_column_wrapper const strings_col1( - {"", - "Different but null!", - "A very long (greater than 128 bytes/char string) to execute a multi hash-step data point in " - "the hash function being tested. This string needed to be longer.", - "All work and no play makes Jack a dull boy", - "!\"#$%&\'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"}, - {1, 0, 0, 1, 0}); - cudf::test::strings_column_wrapper const strings_col2( - {"", - "Another string that is null.", - "Very different... but null", - "All work and no play makes Jack a dull boy", - ""}, - {1, 0, 0, 1, 0}); - - // Nulls with different values should be equal - using limits = std::numeric_limits; - cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); - cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); - - // Nulls with different values should be equal - // Different truthy values should be equal - cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); - - auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); - auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA512HashTestTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA512HashTestTyped, cudf::test::NumericTypes); - -TYPED_TEST(SHA512HashTestTyped, Equality) -{ - cudf::test::fixed_width_column_wrapper const col({0, 127, 1, 2, 8}); - auto const input = cudf::table_view({col}); - - // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA512); - - EXPECT_EQ(input.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -TYPED_TEST(SHA512HashTestTyped, EqualityNulls) -{ - using T = TypeParam; - - // Nulls with different values should be equal - cudf::test::fixed_width_column_wrapper const col1({0, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - cudf::test::fixed_width_column_wrapper const col2({1, 127, 1, 2, 8}, {0, 1, 1, 1, 1}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); - - EXPECT_EQ(input1.num_rows(), output1->size()); - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} - -template -class SHA512HashTestFloatTyped : public cudf::test::BaseFixture {}; - -TYPED_TEST_CASE(SHA512HashTestFloatTyped, cudf::test::FloatingPointTypes); - -TYPED_TEST(SHA512HashTestFloatTyped, TestExtremes) -{ - using T = TypeParam; - T min = std::numeric_limits::min(); - T max = std::numeric_limits::max(); - T nan = std::numeric_limits::quiet_NaN(); - T inf = std::numeric_limits::infinity(); - - cudf::test::fixed_width_column_wrapper const col1( - {T(0.0), T(100.0), T(-100.0), min, max, nan, inf, -inf}); - cudf::test::fixed_width_column_wrapper const col2( - {T(-0.0), T(100.0), T(-100.0), min, max, -nan, inf, -inf}); - - auto const input1 = cudf::table_view({col1}); - auto const input2 = cudf::table_view({col2}); - - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); - - CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); -} From 68b23e0252aed3870a6e283c5c134932bd9113ac Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Tue, 17 Oct 2023 16:28:42 -0700 Subject: [PATCH 097/100] Split into multiple TUs. --- cpp/CMakeLists.txt | 6 +- cpp/src/hash/sha1_hash.cu | 100 +++++++++ cpp/src/hash/sha224_hash.cu | 101 +++++++++ cpp/src/hash/sha256_hash.cu | 102 +++++++++ cpp/src/hash/sha384_hash.cu | 109 ++++++++++ cpp/src/hash/sha512_hash.cu | 109 ++++++++++ cpp/src/hash/{sha_hash.cu => sha_hash.cuh} | 238 +-------------------- 7 files changed, 527 insertions(+), 238 deletions(-) create mode 100644 cpp/src/hash/sha1_hash.cu create mode 100644 cpp/src/hash/sha224_hash.cu create mode 100644 cpp/src/hash/sha256_hash.cu create mode 100644 cpp/src/hash/sha384_hash.cu create mode 100644 cpp/src/hash/sha512_hash.cu rename cpp/src/hash/{sha_hash.cu => sha_hash.cuh} (70%) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 925d29b71e3..0898d29d762 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -347,7 +347,11 @@ add_library( src/hash/md5_hash.cu src/hash/murmurhash3_x86_32.cu src/hash/murmurhash3_x64_128.cu - src/hash/sha_hash.cu + src/hash/sha1_hash.cu + src/hash/sha224_hash.cu + src/hash/sha256_hash.cu + src/hash/sha384_hash.cu + src/hash/sha512_hash.cu src/hash/spark_murmurhash3_x86_32.cu src/hash/xxhash_64.cu src/interop/dlpack.cpp diff --git a/cpp/src/hash/sha1_hash.cu b/cpp/src/hash/sha1_hash.cu new file mode 100644 index 00000000000..c0477343ca1 --- /dev/null +++ b/cpp/src/hash/sha1_hash.cu @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022-2023, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sha_hash.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace cudf { +namespace hashing { +namespace detail { + +namespace { + +struct sha1_hash_state { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; + uint8_t buffer[64]; +}; + +struct SHA1Hash : HashBase { + __device__ inline SHA1Hash(char* result_location) : HashBase(result_location) {} + + // Intermediate data type storing the hash state + using hash_state = sha1_hash_state; + // The word type used by this hash function + using sha_word_type = uint32_t; + // Number of bytes processed in each hash step + static constexpr uint32_t message_chunk_size = 64; + // Digest size in bytes + static constexpr uint32_t digest_size = 40; + // Number of bytes used for the message length + static constexpr uint32_t message_length_size = 8; + + void __device__ inline hash_step(hash_state& state) { sha1_hash_step(state); } + + hash_state state; +}; + +} // namespace + +std::unique_ptr sha1(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result("da39a3ee5e6b4b0d3255bfef95601890afd80709"); + return sha_hash(input, empty_result, stream, mr); +} + +} // namespace detail + +std::unique_ptr sha1(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + return detail::sha1(input, stream, mr); +} + +} // namespace hashing +} // namespace cudf diff --git a/cpp/src/hash/sha224_hash.cu b/cpp/src/hash/sha224_hash.cu new file mode 100644 index 00000000000..af37bde07ab --- /dev/null +++ b/cpp/src/hash/sha224_hash.cu @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022-2023, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sha_hash.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace cudf { +namespace hashing { +namespace detail { + +namespace { + +struct sha224_hash_state { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + uint8_t buffer[64]; +}; + +struct SHA224Hash : HashBase { + __device__ inline SHA224Hash(char* result_location) : HashBase(result_location) {} + + // Intermediate data type storing the hash state + using hash_state = sha224_hash_state; + // The word type used by this hash function + using sha_word_type = uint32_t; + // Number of bytes processed in each hash step + static constexpr uint32_t message_chunk_size = 64; + // Digest size in bytes. This is truncated from SHA-256. + static constexpr uint32_t digest_size = 56; + // Number of bytes used for the message length + static constexpr uint32_t message_length_size = 8; + + void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } + + hash_state state; +}; + +} // namespace + +std::unique_ptr sha224(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); + return sha_hash(input, empty_result, stream, mr); +} + +} // namespace detail + +std::unique_ptr sha224(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + return detail::sha224(input, stream, mr); +} + +} // namespace hashing +} // namespace cudf diff --git a/cpp/src/hash/sha256_hash.cu b/cpp/src/hash/sha256_hash.cu new file mode 100644 index 00000000000..d7a8502337e --- /dev/null +++ b/cpp/src/hash/sha256_hash.cu @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022-2023, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sha_hash.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace cudf { +namespace hashing { +namespace detail { + +namespace { + +struct sha256_hash_state { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint32_t hash_value[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + uint8_t buffer[64]; +}; + +struct SHA256Hash : HashBase { + __device__ inline SHA256Hash(char* result_location) : HashBase(result_location) {} + + // Intermediate data type storing the hash state + using hash_state = sha256_hash_state; + // The word type used by this hash function + using sha_word_type = uint32_t; + // Number of bytes processed in each hash step + static constexpr uint32_t message_chunk_size = 64; + // Digest size in bytes + static constexpr uint32_t digest_size = 64; + // Number of bytes used for the message length + static constexpr uint32_t message_length_size = 8; + + void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } + + hash_state state; +}; + +} // namespace + +std::unique_ptr sha256(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + return sha_hash(input, empty_result, stream, mr); +} + +} // namespace detail + +std::unique_ptr sha256(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + return detail::sha256(input, stream, mr); +} + +} // namespace hashing +} // namespace cudf diff --git a/cpp/src/hash/sha384_hash.cu b/cpp/src/hash/sha384_hash.cu new file mode 100644 index 00000000000..072466da4a8 --- /dev/null +++ b/cpp/src/hash/sha384_hash.cu @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022-2023, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sha_hash.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace cudf { +namespace hashing { +namespace detail { + +namespace { + +struct sha384_hash_state { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4}; + uint8_t buffer[128]; +}; + +struct SHA384Hash : HashBase { + __device__ inline SHA384Hash(char* result_location) : HashBase(result_location) {} + + // Intermediate data type storing the hash state + using hash_state = sha384_hash_state; + // The word type used by this hash function + using sha_word_type = uint64_t; + // Number of bytes processed in each hash step + static constexpr uint32_t message_chunk_size = 128; + // Digest size in bytes. This is truncated from SHA-512. + static constexpr uint32_t digest_size = 96; + // Number of bytes used for the message length + static constexpr uint32_t message_length_size = 16; + + void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } + + hash_state state; +}; + +} // namespace + +std::unique_ptr sha384(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result( + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b9" + "5b"); + return sha_hash(input, empty_result, stream, mr); +} + +} // namespace detail + +std::unique_ptr sha384(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + return detail::sha384(input, stream, mr); +} + +} // namespace hashing +} // namespace cudf diff --git a/cpp/src/hash/sha512_hash.cu b/cpp/src/hash/sha512_hash.cu new file mode 100644 index 00000000000..6971ace4986 --- /dev/null +++ b/cpp/src/hash/sha512_hash.cu @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022-2023, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sha_hash.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace cudf { +namespace hashing { +namespace detail { + +namespace { + +struct sha512_hash_state { + uint64_t message_length = 0; + uint32_t buffer_length = 0; + uint64_t hash_value[8] = {0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179}; + uint8_t buffer[128]; +}; + +struct SHA512Hash : HashBase { + __device__ inline SHA512Hash(char* result_location) : HashBase(result_location) {} + + // Intermediate data type storing the hash state + using hash_state = sha512_hash_state; + // The word type used by this hash function + using sha_word_type = uint64_t; + // Number of bytes processed in each hash step + static constexpr uint32_t message_chunk_size = 128; + // Digest size in bytes + static constexpr uint32_t digest_size = 128; + // Number of bytes used for the message length + static constexpr uint32_t message_length_size = 16; + + void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } + + hash_state state; +}; + +} // namespace + +std::unique_ptr sha512(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + string_scalar const empty_result( + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec" + "2f63b931bd47417a81a538327af927da3e"); + return sha_hash(input, empty_result, stream, mr); +} + +} // namespace detail + +std::unique_ptr sha512(table_view const& input, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + return detail::sha512(input, stream, mr); +} + +} // namespace hashing +} // namespace cudf diff --git a/cpp/src/hash/sha_hash.cu b/cpp/src/hash/sha_hash.cuh similarity index 70% rename from cpp/src/hash/sha_hash.cu rename to cpp/src/hash/sha_hash.cuh index 945840e233c..eeca14f6b3b 100644 --- a/cpp/src/hash/sha_hash.cu +++ b/cpp/src/hash/sha_hash.cuh @@ -45,8 +45,6 @@ namespace cudf { namespace hashing { namespace detail { -namespace { - const __constant__ uint32_t sha256_hash_constants[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, @@ -268,57 +266,6 @@ struct HasherDispatcher { } }; -struct sha1_hash_state { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; - uint8_t buffer[64]; -}; - -struct sha224_hash_state { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[8] = { - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; - uint8_t buffer[64]; -}; - -struct sha256_hash_state { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint32_t hash_value[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - uint8_t buffer[64]; -}; - -struct sha384_hash_state { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, - 0x629a292a367cd507, - 0x9159015a3070dd17, - 0x152fecd8f70e5939, - 0x67332667ffc00b31, - 0x8eb44a8768581511, - 0xdb0c2e0d64f98fa7, - 0x47b5481dbefa4fa4}; - uint8_t buffer[128]; -}; - -struct sha512_hash_state { - uint64_t message_length = 0; - uint32_t buffer_length = 0; - uint64_t hash_value[8] = {0x6a09e667f3bcc908, - 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, - 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, - 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, - 0x5be0cd19137e2179}; - uint8_t buffer[128]; -}; - /** * @brief Core SHA-1 algorithm implementation. Processes a single 512-bit chunk, * updating the hash value so far. Does not zero out the buffer contents. @@ -518,103 +465,8 @@ void __device__ inline sha512_hash_step(hash_state& state) state.buffer_length = 0; } -struct SHA1Hash : HashBase { - __device__ inline SHA1Hash(char* result_location) : HashBase(result_location) {} - - // Intermediate data type storing the hash state - using hash_state = sha1_hash_state; - // The word type used by this hash function - using sha_word_type = uint32_t; - // Number of bytes processed in each hash step - static constexpr uint32_t message_chunk_size = 64; - // Digest size in bytes - static constexpr uint32_t digest_size = 40; - // Number of bytes used for the message length - static constexpr uint32_t message_length_size = 8; - - void __device__ inline hash_step(hash_state& state) { sha1_hash_step(state); } - - hash_state state; -}; - -struct SHA224Hash : HashBase { - __device__ inline SHA224Hash(char* result_location) : HashBase(result_location) {} - - // Intermediate data type storing the hash state - using hash_state = sha224_hash_state; - // The word type used by this hash function - using sha_word_type = uint32_t; - // Number of bytes processed in each hash step - static constexpr uint32_t message_chunk_size = 64; - // Digest size in bytes. This is truncated from SHA-256. - static constexpr uint32_t digest_size = 56; - // Number of bytes used for the message length - static constexpr uint32_t message_length_size = 8; - - void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } - - hash_state state; -}; - -struct SHA256Hash : HashBase { - __device__ inline SHA256Hash(char* result_location) : HashBase(result_location) {} - - // Intermediate data type storing the hash state - using hash_state = sha256_hash_state; - // The word type used by this hash function - using sha_word_type = uint32_t; - // Number of bytes processed in each hash step - static constexpr uint32_t message_chunk_size = 64; - // Digest size in bytes - static constexpr uint32_t digest_size = 64; - // Number of bytes used for the message length - static constexpr uint32_t message_length_size = 8; - - void __device__ inline hash_step(hash_state& state) { sha256_hash_step(state); } - - hash_state state; -}; - -struct SHA384Hash : HashBase { - __device__ inline SHA384Hash(char* result_location) : HashBase(result_location) {} - - // Intermediate data type storing the hash state - using hash_state = sha384_hash_state; - // The word type used by this hash function - using sha_word_type = uint64_t; - // Number of bytes processed in each hash step - static constexpr uint32_t message_chunk_size = 128; - // Digest size in bytes. This is truncated from SHA-512. - static constexpr uint32_t digest_size = 96; - // Number of bytes used for the message length - static constexpr uint32_t message_length_size = 16; - - void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } - - hash_state state; -}; - -struct SHA512Hash : HashBase { - __device__ inline SHA512Hash(char* result_location) : HashBase(result_location) {} - - // Intermediate data type storing the hash state - using hash_state = sha512_hash_state; - // The word type used by this hash function - using sha_word_type = uint64_t; - // Number of bytes processed in each hash step - static constexpr uint32_t message_chunk_size = 128; - // Digest size in bytes - static constexpr uint32_t digest_size = 128; - // Number of bytes used for the message length - static constexpr uint32_t message_length_size = 16; - - void __device__ inline hash_step(hash_state& state) { sha512_hash_step(state); } - - hash_state state; -}; - // SHA supported leaf data type check -bool sha_leaf_type_check(data_type dt) +bool inline sha_leaf_type_check(data_type dt) { return (is_fixed_width(dt) && !is_chrono(dt)) || (dt.id() == type_id::STRING); } @@ -680,94 +532,6 @@ std::unique_ptr sha_hash(table_view const& input, input.num_rows(), std::move(offsets_column), std::move(chars_column), 0, {}); } -} // namespace - -std::unique_ptr sha1(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - string_scalar const empty_result("da39a3ee5e6b4b0d3255bfef95601890afd80709"); - return sha_hash(input, empty_result, stream, mr); -} - -std::unique_ptr sha224(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - string_scalar const empty_result("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"); - return sha_hash(input, empty_result, stream, mr); -} - -std::unique_ptr sha256(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - string_scalar const empty_result( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - return sha_hash(input, empty_result, stream, mr); -} - -std::unique_ptr sha384(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - string_scalar const empty_result( - "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b9" - "5b"); - return sha_hash(input, empty_result, stream, mr); -} - -std::unique_ptr sha512(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - string_scalar const empty_result( - "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec" - "2f63b931bd47417a81a538327af927da3e"); - return sha_hash(input, empty_result, stream, mr); -} - } // namespace detail - -std::unique_ptr sha1(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - CUDF_FUNC_RANGE(); - return detail::sha1(input, stream, mr); -} - -std::unique_ptr sha224(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - CUDF_FUNC_RANGE(); - return detail::sha224(input, stream, mr); -} - -std::unique_ptr sha256(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - CUDF_FUNC_RANGE(); - return detail::sha256(input, stream, mr); -} - -std::unique_ptr sha384(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - CUDF_FUNC_RANGE(); - return detail::sha384(input, stream, mr); -} - -std::unique_ptr sha512(table_view const& input, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - CUDF_FUNC_RANGE(); - return detail::sha512(input, stream, mr); -} - } // namespace hashing } // namespace cudf From 9fd9e8d4d9f9e59c825b8eec7c9d4375319f0a1c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Wed, 18 Oct 2023 09:04:06 -0700 Subject: [PATCH 098/100] Update tests. --- cpp/tests/hashing/sha1_test.cpp | 38 +++++++++++++++---------------- cpp/tests/hashing/sha224_test.cpp | 38 +++++++++++++++---------------- cpp/tests/hashing/sha256_test.cpp | 38 +++++++++++++++---------------- cpp/tests/hashing/sha384_test.cpp | 38 +++++++++++++++---------------- cpp/tests/hashing/sha512_test.cpp | 38 +++++++++++++++---------------- 5 files changed, 95 insertions(+), 95 deletions(-) diff --git a/cpp/tests/hashing/sha1_test.cpp b/cpp/tests/hashing/sha1_test.cpp index 45949b27356..6168fb06909 100644 --- a/cpp/tests/hashing/sha1_test.cpp +++ b/cpp/tests/hashing/sha1_test.cpp @@ -31,12 +31,12 @@ TEST_F(SHA1HashTest, EmptyTable) { auto const empty_table = cudf::table_view{}; auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); + auto const output_empty_table = cudf::hashing::sha1(empty_table); EXPECT_EQ(empty_column->size(), output_empty_table->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA1); + auto const output_one_empty_column = cudf::hashing::sha1(empty_table); EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); } @@ -84,8 +84,8 @@ TEST_F(SHA1HashTest, MultiValue) auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha1_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA1); - auto const sha1_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA1); + auto const sha1_string_output1 = cudf::hashing::sha1(string_input1); + auto const sha1_string_output2 = cudf::hashing::sha1(string_input2); EXPECT_EQ(string_input1.num_rows(), sha1_string_output1->size()); EXPECT_EQ(string_input2.num_rows(), sha1_string_output2->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_string_output1->view(), sha1_string_results1); @@ -93,8 +93,8 @@ TEST_F(SHA1HashTest, MultiValue) auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha1_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const sha1_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + auto const sha1_output1 = cudf::hashing::sha1(input1); + auto const sha1_output2 = cudf::hashing::sha1(input2); EXPECT_EQ(input1.num_rows(), sha1_output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha1_output1->view(), sha1_output2->view()); } @@ -116,25 +116,25 @@ TEST_F(SHA1HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 0}); + {1, 0, 0, 1, 1}); // empty string is equivalent to null // Nulls with different values should be equal using limits = std::numeric_limits; cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); // Nulls with different values should be equal - // Different truthy values should be equal + // Different truth values should be equal cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + auto const output1 = cudf::hashing::sha1(input1); + auto const output2 = cudf::hashing::sha1(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -151,8 +151,8 @@ TYPED_TEST(SHA1HashTestTyped, Equality) auto const input = cudf::table_view({col}); // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA1); + auto const output1 = cudf::hashing::sha1(input); + auto const output2 = cudf::hashing::sha1(input); EXPECT_EQ(input.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -169,8 +169,8 @@ TYPED_TEST(SHA1HashTestTyped, EqualityNulls) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + auto const output1 = cudf::hashing::sha1(input1); + auto const output2 = cudf::hashing::sha1(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -197,8 +197,8 @@ TYPED_TEST(SHA1HashTestFloatTyped, TestExtremes) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA1); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA1); + auto const output1 = cudf::hashing::sha1(input1); + auto const output2 = cudf::hashing::sha1(input2); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } diff --git a/cpp/tests/hashing/sha224_test.cpp b/cpp/tests/hashing/sha224_test.cpp index 3d530ec74d8..3192107e8ec 100644 --- a/cpp/tests/hashing/sha224_test.cpp +++ b/cpp/tests/hashing/sha224_test.cpp @@ -31,12 +31,12 @@ TEST_F(SHA224HashTest, EmptyTable) { auto const empty_table = cudf::table_view{}; auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); + auto const output_empty_table = cudf::hashing::sha224(empty_table); EXPECT_EQ(empty_column->size(), output_empty_table->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA224); + auto const output_one_empty_column = cudf::hashing::sha224(empty_table); EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); } @@ -84,8 +84,8 @@ TEST_F(SHA224HashTest, MultiValue) auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha224_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA224); - auto const sha224_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA224); + auto const sha224_string_output1 = cudf::hashing::sha224(string_input1); + auto const sha224_string_output2 = cudf::hashing::sha224(string_input2); EXPECT_EQ(string_input1.num_rows(), sha224_string_output1->size()); EXPECT_EQ(string_input2.num_rows(), sha224_string_output2->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_string_output1->view(), sha224_string_results1); @@ -93,8 +93,8 @@ TEST_F(SHA224HashTest, MultiValue) auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha224_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const sha224_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + auto const sha224_output1 = cudf::hashing::sha224(input1); + auto const sha224_output2 = cudf::hashing::sha224(input2); EXPECT_EQ(input1.num_rows(), sha224_output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha224_output1->view(), sha224_output2->view()); } @@ -116,25 +116,25 @@ TEST_F(SHA224HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 0}); + {1, 0, 0, 1, 1}); // empty string is equivalent to null // Nulls with different values should be equal using limits = std::numeric_limits; cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); // Nulls with different values should be equal - // Different truthy values should be equal + // Different truth values should be equal cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + auto const output1 = cudf::hashing::sha224(input1); + auto const output2 = cudf::hashing::sha224(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -151,8 +151,8 @@ TYPED_TEST(SHA224HashTestTyped, Equality) auto const input = cudf::table_view({col}); // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA224); + auto const output1 = cudf::hashing::sha224(input); + auto const output2 = cudf::hashing::sha224(input); EXPECT_EQ(input.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -169,8 +169,8 @@ TYPED_TEST(SHA224HashTestTyped, EqualityNulls) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + auto const output1 = cudf::hashing::sha224(input1); + auto const output2 = cudf::hashing::sha224(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -197,8 +197,8 @@ TYPED_TEST(SHA224HashTestFloatTyped, TestExtremes) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA224); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA224); + auto const output1 = cudf::hashing::sha224(input1); + auto const output2 = cudf::hashing::sha224(input2); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } diff --git a/cpp/tests/hashing/sha256_test.cpp b/cpp/tests/hashing/sha256_test.cpp index e8951395819..df35755831c 100644 --- a/cpp/tests/hashing/sha256_test.cpp +++ b/cpp/tests/hashing/sha256_test.cpp @@ -31,12 +31,12 @@ TEST_F(SHA256HashTest, EmptyTable) { auto const empty_table = cudf::table_view{}; auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); + auto const output_empty_table = cudf::hashing::sha256(empty_table); EXPECT_EQ(empty_column->size(), output_empty_table->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA256); + auto const output_one_empty_column = cudf::hashing::sha256(empty_table); EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); } @@ -84,8 +84,8 @@ TEST_F(SHA256HashTest, MultiValue) auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha256_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA256); - auto const sha256_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA256); + auto const sha256_string_output1 = cudf::hashing::sha256(string_input1); + auto const sha256_string_output2 = cudf::hashing::sha256(string_input2); EXPECT_EQ(string_input1.num_rows(), sha256_string_output1->size()); EXPECT_EQ(string_input2.num_rows(), sha256_string_output2->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_string_output1->view(), sha256_string_results1); @@ -93,8 +93,8 @@ TEST_F(SHA256HashTest, MultiValue) auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha256_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const sha256_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + auto const sha256_output1 = cudf::hashing::sha256(input1); + auto const sha256_output2 = cudf::hashing::sha256(input2); EXPECT_EQ(input1.num_rows(), sha256_output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha256_output1->view(), sha256_output2->view()); } @@ -116,25 +116,25 @@ TEST_F(SHA256HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 0}); + {1, 0, 0, 1, 1}); // empty string is equivalent to null // Nulls with different values should be equal using limits = std::numeric_limits; cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); // Nulls with different values should be equal - // Different truthy values should be equal + // Different truth values should be equal cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + auto const output1 = cudf::hashing::sha256(input1); + auto const output2 = cudf::hashing::sha256(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -151,8 +151,8 @@ TYPED_TEST(SHA256HashTestTyped, Equality) auto const input = cudf::table_view({col}); // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA256); + auto const output1 = cudf::hashing::sha256(input); + auto const output2 = cudf::hashing::sha256(input); EXPECT_EQ(input.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -169,8 +169,8 @@ TYPED_TEST(SHA256HashTestTyped, EqualityNulls) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + auto const output1 = cudf::hashing::sha256(input1); + auto const output2 = cudf::hashing::sha256(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -197,8 +197,8 @@ TYPED_TEST(SHA256HashTestFloatTyped, TestExtremes) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA256); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA256); + auto const output1 = cudf::hashing::sha256(input1); + auto const output2 = cudf::hashing::sha256(input2); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } diff --git a/cpp/tests/hashing/sha384_test.cpp b/cpp/tests/hashing/sha384_test.cpp index 6b7d9eeed49..435a95bb4a8 100644 --- a/cpp/tests/hashing/sha384_test.cpp +++ b/cpp/tests/hashing/sha384_test.cpp @@ -31,12 +31,12 @@ TEST_F(SHA384HashTest, EmptyTable) { auto const empty_table = cudf::table_view{}; auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); + auto const output_empty_table = cudf::hashing::sha384(empty_table); EXPECT_EQ(empty_column->size(), output_empty_table->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA384); + auto const output_one_empty_column = cudf::hashing::sha384(empty_table); EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); } @@ -100,8 +100,8 @@ TEST_F(SHA384HashTest, MultiValue) auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha384_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA384); - auto const sha384_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA384); + auto const sha384_string_output1 = cudf::hashing::sha384(string_input1); + auto const sha384_string_output2 = cudf::hashing::sha384(string_input2); EXPECT_EQ(string_input1.num_rows(), sha384_string_output1->size()); EXPECT_EQ(string_input2.num_rows(), sha384_string_output2->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_string_output1->view(), sha384_string_results1, verbosity); @@ -109,8 +109,8 @@ TEST_F(SHA384HashTest, MultiValue) auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha384_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const sha384_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + auto const sha384_output1 = cudf::hashing::sha384(input1); + auto const sha384_output2 = cudf::hashing::sha384(input2); EXPECT_EQ(input1.num_rows(), sha384_output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha384_output1->view(), sha384_output2->view(), verbosity); } @@ -132,25 +132,25 @@ TEST_F(SHA384HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 0}); + {1, 0, 0, 1, 1}); // empty string is equivalent to null // Nulls with different values should be equal using limits = std::numeric_limits; cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); // Nulls with different values should be equal - // Different truthy values should be equal + // Different truth values should be equal cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + auto const output1 = cudf::hashing::sha384(input1); + auto const output2 = cudf::hashing::sha384(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -167,8 +167,8 @@ TYPED_TEST(SHA384HashTestTyped, Equality) auto const input = cudf::table_view({col}); // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA384); + auto const output1 = cudf::hashing::sha384(input); + auto const output2 = cudf::hashing::sha384(input); EXPECT_EQ(input.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -185,8 +185,8 @@ TYPED_TEST(SHA384HashTestTyped, EqualityNulls) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + auto const output1 = cudf::hashing::sha384(input1); + auto const output2 = cudf::hashing::sha384(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -213,8 +213,8 @@ TYPED_TEST(SHA384HashTestFloatTyped, TestExtremes) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA384); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA384); + auto const output1 = cudf::hashing::sha384(input1); + auto const output2 = cudf::hashing::sha384(input2); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } diff --git a/cpp/tests/hashing/sha512_test.cpp b/cpp/tests/hashing/sha512_test.cpp index 7721f683705..4e0b76999b7 100644 --- a/cpp/tests/hashing/sha512_test.cpp +++ b/cpp/tests/hashing/sha512_test.cpp @@ -31,12 +31,12 @@ TEST_F(SHA512HashTest, EmptyTable) { auto const empty_table = cudf::table_view{}; auto const empty_column = cudf::make_empty_column(cudf::data_type(cudf::type_id::STRING)); - auto const output_empty_table = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); + auto const output_empty_table = cudf::hashing::sha512(empty_table); EXPECT_EQ(empty_column->size(), output_empty_table->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_empty_table->view()); auto const table_one_empty_column = cudf::table_view{{empty_column->view()}}; - auto const output_one_empty_column = cudf::hash(empty_table, cudf::hash_id::HASH_SHA512); + auto const output_one_empty_column = cudf::hashing::sha512(empty_table); EXPECT_EQ(empty_column->size(), output_one_empty_column->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(empty_column->view(), output_one_empty_column->view()); } @@ -100,8 +100,8 @@ TEST_F(SHA512HashTest, MultiValue) auto const string_input1 = cudf::table_view({strings_col}); auto const string_input2 = cudf::table_view({strings_col, strings_col}); - auto const sha512_string_output1 = cudf::hash(string_input1, cudf::hash_id::HASH_SHA512); - auto const sha512_string_output2 = cudf::hash(string_input2, cudf::hash_id::HASH_SHA512); + auto const sha512_string_output1 = cudf::hashing::sha512(string_input1); + auto const sha512_string_output2 = cudf::hashing::sha512(string_input2); EXPECT_EQ(string_input1.num_rows(), sha512_string_output1->size()); EXPECT_EQ(string_input2.num_rows(), sha512_string_output2->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_string_output1->view(), sha512_string_results1, verbosity); @@ -109,8 +109,8 @@ TEST_F(SHA512HashTest, MultiValue) auto const input1 = cudf::table_view({strings_col, ints_col, bools_col1}); auto const input2 = cudf::table_view({strings_col, ints_col, bools_col2}); - auto const sha512_output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const sha512_output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + auto const sha512_output1 = cudf::hashing::sha512(input1); + auto const sha512_output2 = cudf::hashing::sha512(input2); EXPECT_EQ(input1.num_rows(), sha512_output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(sha512_output1->view(), sha512_output2->view(), verbosity); } @@ -132,25 +132,25 @@ TEST_F(SHA512HashTest, MultiValueNulls) "Very different... but null", "All work and no play makes Jack a dull boy", ""}, - {1, 0, 0, 1, 0}); + {1, 0, 0, 1, 1}); // empty string is equivalent to null // Nulls with different values should be equal using limits = std::numeric_limits; cudf::test::fixed_width_column_wrapper const ints_col1( - {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 0}); + {0, 100, -100, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); cudf::test::fixed_width_column_wrapper const ints_col2( - {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 0, 1}); + {0, -200, 200, limits::min(), limits::max()}, {1, 0, 0, 1, 1}); // Nulls with different values should be equal - // Different truthy values should be equal + // Different truth values should be equal cudf::test::fixed_width_column_wrapper const bools_col1({0, 1, 0, 1, 1}, {1, 1, 0, 0, 1}); - cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 1, 0}); + cudf::test::fixed_width_column_wrapper const bools_col2({0, 2, 1, 0, 255}, {1, 1, 0, 0, 1}); auto const input1 = cudf::table_view({strings_col1, ints_col1, bools_col1}); auto const input2 = cudf::table_view({strings_col2, ints_col2, bools_col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + auto const output1 = cudf::hashing::sha512(input1); + auto const output2 = cudf::hashing::sha512(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -167,8 +167,8 @@ TYPED_TEST(SHA512HashTestTyped, Equality) auto const input = cudf::table_view({col}); // Hash of same input should be equal - auto const output1 = cudf::hash(input, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input, cudf::hash_id::HASH_SHA512); + auto const output1 = cudf::hashing::sha512(input); + auto const output2 = cudf::hashing::sha512(input); EXPECT_EQ(input.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -185,8 +185,8 @@ TYPED_TEST(SHA512HashTestTyped, EqualityNulls) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + auto const output1 = cudf::hashing::sha512(input1); + auto const output2 = cudf::hashing::sha512(input2); EXPECT_EQ(input1.num_rows(), output1->size()); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); @@ -213,8 +213,8 @@ TYPED_TEST(SHA512HashTestFloatTyped, TestExtremes) auto const input1 = cudf::table_view({col1}); auto const input2 = cudf::table_view({col2}); - auto const output1 = cudf::hash(input1, cudf::hash_id::HASH_SHA512); - auto const output2 = cudf::hash(input2, cudf::hash_id::HASH_SHA512); + auto const output1 = cudf::hashing::sha512(input1); + auto const output2 = cudf::hashing::sha512(input2); CUDF_TEST_EXPECT_COLUMNS_EQUAL(output1->view(), output2->view()); } From 1442bfd74c0d5fe3cdf0e958bc89d918d89cb56c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Nov 2023 10:48:57 -0800 Subject: [PATCH 099/100] Add alignment to avoid compiler bug. --- cpp/src/hash/sha384_hash.cu | 3 ++- cpp/src/hash/sha512_hash.cu | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/src/hash/sha384_hash.cu b/cpp/src/hash/sha384_hash.cu index 072466da4a8..83c7ceb4703 100644 --- a/cpp/src/hash/sha384_hash.cu +++ b/cpp/src/hash/sha384_hash.cu @@ -50,7 +50,8 @@ namespace detail { namespace { -struct sha384_hash_state { +// Need alignas(16) to avoid compiler bug. +struct alignas(16) sha384_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint64_t hash_value[8] = {0xcbbb9d5dc1059ed8, diff --git a/cpp/src/hash/sha512_hash.cu b/cpp/src/hash/sha512_hash.cu index 6971ace4986..f705b25a45f 100644 --- a/cpp/src/hash/sha512_hash.cu +++ b/cpp/src/hash/sha512_hash.cu @@ -50,7 +50,8 @@ namespace detail { namespace { -struct sha512_hash_state { +// Need alignas(16) to avoid compiler bug. +struct alignas(16) sha512_hash_state { uint64_t message_length = 0; uint32_t buffer_length = 0; uint64_t hash_value[8] = {0x6a09e667f3bcc908, From 47ccdd2648b77a0e1f20de53c00b11638c7b7d60 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Thu, 9 Nov 2023 14:00:05 -0800 Subject: [PATCH 100/100] Remove extra copy of device function. --- cpp/src/hash/md5_hash.cu | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/cpp/src/hash/md5_hash.cu b/cpp/src/hash/md5_hash.cu index 4e25f9f8c23..868a0ad34de 100644 --- a/cpp/src/hash/md5_hash.cu +++ b/cpp/src/hash/md5_hash.cu @@ -108,29 +108,6 @@ auto __device__ inline get_element_pointer_and_size(string_view const& element) return thrust::make_pair(reinterpret_cast(element.data()), element.size_bytes()); } -/** - * Modified GPU implementation of - * https://johnnylee-sde.github.io/Fast-unsigned-integer-to-hex-string/ - * Copyright (c) 2015 Barry Clark - * Licensed under the MIT license. - * See file LICENSE for detail or copy at https://opensource.org/licenses/MIT - */ -void __device__ inline uint32ToLowercaseHexString(uint32_t num, char* destination) -{ - // Transform 0xABCD'1234 => 0x0000'ABCD'0000'1234 => 0x0B0A'0D0C'0201'0403 - uint64_t x = num; - x = ((x & 0xFFFF'0000u) << 16) | ((x & 0xFFFF)); - x = ((x & 0x000F'0000'000Fu) << 8) | ((x & 0x00F0'0000'00F0u) >> 4) | - ((x & 0x0F00'0000'0F00u) << 16) | ((x & 0xF000'0000'F000) << 4); - - // Calculate a mask of ascii value offsets for bytes that contain alphabetical hex digits - uint64_t offsets = (((x + 0x0606'0606'0606'0606) >> 4) & 0x0101'0101'0101'0101) * 0x27; - - x |= 0x3030'3030'3030'3030; - x += offsets; - std::memcpy(destination, reinterpret_cast(&x), 8); -} - // The MD5 algorithm and its hash/shift constants are officially specified in // RFC 1321. For convenience, these values can also be found on Wikipedia: // https://en.wikipedia.org/wiki/MD5