-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added hash template class for 256 & 512 bit hashes
* Added optional picosha2 dependency for calculating hashes
- Loading branch information
Showing
6 changed files
with
396 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,3 +22,4 @@ | |
#include "../ctle/types.h" | ||
#include "../ctle/util.h" | ||
#include "../ctle/uuid.h" | ||
#include "../ctle/hash.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// ctle Copyright (c) 2021 Ulrik Lindahl | ||
// Licensed under the MIT license https://github.com/Cooolrik/ctle/blob/main/LICENSE | ||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <functional> | ||
#include <iosfwd> | ||
|
||
#include "status.h" | ||
|
||
namespace ctle | ||
{ | ||
|
||
// define hash for message digests, either 256 or 512 bits in size (32 or 64 bytes) | ||
template<size_t _Size> | ||
struct hash | ||
{ | ||
static_assert( _Size == 256 || _Size == 512 , "Hash size must be 256 or 512"); | ||
static constexpr const size_t hash_size = _Size; | ||
|
||
union | ||
{ | ||
uint64_t _data_q[_Size/64] = {}; | ||
uint8_t data[_Size/8]; | ||
}; | ||
|
||
// compare operators | ||
bool operator<( const hash &other ) const noexcept; | ||
bool operator==( const hash &other ) const noexcept; | ||
bool operator!=( const hash &other ) const noexcept; | ||
}; | ||
|
||
template<size_t _Size> | ||
inline bool hash<_Size>::operator<( const hash &right ) const noexcept | ||
{ | ||
const uint8_t *u1 = this->data; | ||
const uint8_t *u2 = right.data; | ||
|
||
// hash values are stored big-endian, so MSB is first byte (index 0), LSB is last byte (index 31 or 63) | ||
size_t n = _Size/8; | ||
do | ||
{ | ||
if( *u1 != *u2 ) // not equal, early exit, check if more or less than | ||
{ | ||
if( *u1 < *u2 ) | ||
return true; // less than | ||
else | ||
return false; // more than | ||
} | ||
++u1; | ||
++u2; | ||
--n; | ||
} while( n>0 ); | ||
|
||
return false; // equal, so not less | ||
}; | ||
|
||
template<size_t _Size> | ||
inline bool hash<_Size>::operator==( const hash &right ) const noexcept | ||
{ | ||
const uint64_t *u1 = this->_data_q; | ||
const uint64_t *u2 = right._data_q; | ||
|
||
// hash values are stored big-endian, so MSB is first byte (index 0), LSB is last byte (index 31 or 63) | ||
size_t n = _Size/64; | ||
do | ||
{ | ||
if( *u1 != *u2 ) // not equal, return false | ||
{ | ||
return false; | ||
} | ||
++u1; | ||
++u2; | ||
--n; | ||
} while( n>0 ); | ||
|
||
return true; // equal | ||
}; | ||
|
||
template<size_t _Size> | ||
inline bool hash<_Size>::operator!=( const hash &right ) const noexcept | ||
{ | ||
return !this->operator==( right ); | ||
}; | ||
|
||
template<size_t _Size> | ||
inline size_t calculate_size_hash( const hash<_Size> &value ) | ||
{ | ||
static_assert( sizeof( std::size_t ) == sizeof( std::uint64_t ), "The hashing code only works for 64bit size_t" ); | ||
size_t hval = value._data_q[0]; | ||
for( size_t inx=1; inx<(_Size/64); ++inx ) | ||
{ | ||
hval ^= value._data_q[inx]; | ||
} | ||
return hval; | ||
} | ||
|
||
status calculate_sha256_hash( uint8_t destDigest[32], const uint8_t *srcData, size_t srcDataLength ); | ||
status calculate_sha256_hash( hash<256> &destHash, const uint8_t *srcData, size_t srcDataLength ); | ||
|
||
} | ||
//namespace ctle | ||
|
||
template <> | ||
struct std::hash<ctle::hash<256>> | ||
{ | ||
std::size_t operator()( const ctle::hash<256> &val ) const noexcept | ||
{ | ||
return ctle::calculate_size_hash<256>( val ); | ||
} | ||
}; | ||
|
||
template <> | ||
struct std::hash<ctle::hash<512>> | ||
{ | ||
std::size_t operator()( const ctle::hash<512> &val ) const noexcept | ||
{ | ||
return ctle::calculate_size_hash<512>( val ); | ||
} | ||
}; | ||
|
||
std::ostream &operator<<( std::ostream &os, const ctle::hash<256> &_hash ); | ||
std::ostream &operator<<( std::ostream &os, const ctle::hash<512> &_hash ); | ||
|
||
#ifdef CTLE_IMPLEMENTATION | ||
|
||
#include <random> | ||
#include <algorithm> | ||
#include <memory> | ||
#include <array> | ||
|
||
#include "string_funcs.h" | ||
|
||
namespace ctle | ||
{ | ||
|
||
template <> std::string value_to_hex_string<hash<256>>( const hash<256> &value ) | ||
{ | ||
static_assert( sizeof( value ) == 32, "Error: hash<256> is assumed to be of size 32." ); | ||
return bytes_to_hex_string( &value, 32 ); | ||
} | ||
|
||
template <> std::string value_to_hex_string<hash<512>>( const hash<512> &value ) | ||
{ | ||
static_assert( sizeof( value ) == 64, "Error: hash<512> is assumed to be of size 64." ); | ||
return bytes_to_hex_string( &value, 64 ); | ||
} | ||
|
||
template <> hash<256> hex_string_to_value<hash<256>>( const char *hex_string ) | ||
{ | ||
hash<256> value; | ||
static_assert( sizeof( value ) == 32, "Error: hash<256> is assumed to be of size 32." ); | ||
hex_string_to_bytes( &value, hex_string, 32 ); | ||
return value; | ||
} | ||
|
||
template <> hash<512> hex_string_to_value<hash<512>>( const char *hex_string ) | ||
{ | ||
hash<512> value; | ||
static_assert( sizeof( value ) == 64, "Error: hash<512> is assumed to be of size 64." ); | ||
hex_string_to_bytes( &value, hex_string, 64 ); | ||
return value; | ||
} | ||
|
||
// if picosha-2 is included, implement the hash generation function for hash<256> | ||
#ifdef PICOSHA2_H | ||
|
||
status calculate_sha256_hash( uint8_t destDigest[32], const uint8_t *srcData, size_t srcDataLength ) | ||
{ | ||
picosha2::hash256_one_by_one hasher; | ||
|
||
hasher.process( srcData, srcData + srcDataLength ); | ||
hasher.finish(); | ||
hasher.get_hash_bytes( destDigest, destDigest + 32 ); | ||
|
||
return status::ok; | ||
} | ||
|
||
status calculate_sha256_hash( hash<256> &destHash, const uint8_t *srcData, size_t srcDataLength ) | ||
{ | ||
return calculate_sha256_hash( destHash.data, srcData, srcDataLength ); | ||
} | ||
#endif | ||
|
||
} | ||
//namespace ctle | ||
|
||
std::ostream &operator<<( std::ostream &os, const ctle::hash<256> &_hash ) | ||
{ | ||
os << ctle::value_to_hex_string( _hash ); | ||
return os; | ||
} | ||
|
||
std::ostream &operator<<( std::ostream &os, const ctle::hash<512> &_hash ) | ||
{ | ||
os << ctle::value_to_hex_string( _hash ); | ||
return os; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.