sha3.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #ifndef BOOST_HASH2_SHA3_HPP_INCLUDED
  2. #define BOOST_HASH2_SHA3_HPP_INCLUDED
  3. // Copyright 2025 Christian Mazakas.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. //
  7. // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
  8. // https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/C/Keccak-readable-and-compact.c
  9. // https://keccak.team/files/Keccak-reference-3.0.pdf
  10. #include <boost/hash2/digest.hpp>
  11. #include <boost/hash2/hmac.hpp>
  12. #include <boost/hash2/detail/keccak.hpp>
  13. #include <boost/assert.hpp>
  14. #include <boost/config.hpp>
  15. #include <cstdint>
  16. namespace boost
  17. {
  18. namespace hash2
  19. {
  20. namespace detail
  21. {
  22. template<std::uint8_t PaddingDelim, int C, int D>
  23. struct keccak_base
  24. {
  25. private:
  26. static constexpr int R = 1600 - C;
  27. unsigned char state_[ 200 ] = {};
  28. std::size_t m_ = 0;
  29. bool finalized_ = false;
  30. public:
  31. using result_type = digest<D / 8>;
  32. static constexpr std::size_t block_size = R / 8;
  33. void update( void const* pv, std::size_t n )
  34. {
  35. unsigned char const* p = static_cast<unsigned char const*>( pv );
  36. update( p, n );
  37. }
  38. BOOST_HASH2_SHA3_CONSTEXPR void update( unsigned char const* p, std::size_t n )
  39. {
  40. finalized_ = false;
  41. auto const block_len = R / 8;
  42. if( m_ > 0 )
  43. {
  44. std::size_t k = block_len - m_;
  45. if( n < k )
  46. {
  47. k = n;
  48. }
  49. for( std::size_t i = 0; i < k; ++i )
  50. {
  51. state_[ m_ + i ] ^= p[ i ];
  52. }
  53. p += k;
  54. n -= k;
  55. m_ += k;
  56. if( m_ < block_len ) return;
  57. BOOST_ASSERT( m_ == block_len );
  58. keccak_permute( state_ );
  59. m_ = 0;
  60. }
  61. while( n >= block_len )
  62. {
  63. for( int i = 0; i < block_len; ++i )
  64. {
  65. state_[ i ] ^= p[ i ];
  66. }
  67. keccak_permute( state_ );
  68. p += block_len;
  69. n -= block_len;
  70. }
  71. BOOST_ASSERT( n < block_len );
  72. if( n > 0 )
  73. {
  74. for( std::size_t i = 0; i < n; ++i )
  75. {
  76. state_[ i ] ^= p[ i ];
  77. }
  78. m_ = n;
  79. }
  80. BOOST_ASSERT( m_ == n % block_len );
  81. }
  82. BOOST_HASH2_SHA3_CONSTEXPR result_type result()
  83. {
  84. result_type digest;
  85. if( !finalized_ )
  86. {
  87. state_[ m_ ] ^= PaddingDelim;
  88. state_[ R / 8 - 1 ] ^= 0x80;
  89. m_ = 0;
  90. finalized_ = true;
  91. }
  92. keccak_permute( state_ );
  93. detail::memcpy( digest.data(), state_, digest.size() );
  94. return digest;
  95. }
  96. };
  97. #if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
  98. template<std::uint8_t PaddingDelim, int C, int D>
  99. constexpr std::size_t keccak_base<PaddingDelim, C, D>::block_size;
  100. #endif
  101. } // namespace detail
  102. class sha3_224: public detail::keccak_base<0x06, 2 * 224, 224>
  103. {
  104. public:
  105. BOOST_HASH2_SHA3_CONSTEXPR sha3_224()
  106. {
  107. }
  108. BOOST_HASH2_SHA3_CONSTEXPR explicit sha3_224( std::uint64_t seed )
  109. {
  110. if( seed != 0 )
  111. {
  112. unsigned char tmp[ 8 ] = {};
  113. detail::write64le( tmp, seed );
  114. update( tmp, 8 );
  115. result();
  116. update( tmp, 0 ); // sets finalized_ to false
  117. }
  118. }
  119. BOOST_HASH2_SHA3_CONSTEXPR sha3_224( unsigned char const * p, std::size_t n )
  120. {
  121. if( n != 0 )
  122. {
  123. update( p, n );
  124. result();
  125. update( p, 0 ); // sets finalized_ to false
  126. }
  127. }
  128. sha3_224( void const * p, std::size_t n ): sha3_224( static_cast<unsigned char const*>( p ), n )
  129. {
  130. }
  131. };
  132. class sha3_256: public detail::keccak_base<0x06, 2 * 256, 256>
  133. {
  134. public:
  135. BOOST_HASH2_SHA3_CONSTEXPR sha3_256()
  136. {
  137. }
  138. BOOST_HASH2_SHA3_CONSTEXPR explicit sha3_256( std::uint64_t seed )
  139. {
  140. if( seed != 0 )
  141. {
  142. unsigned char tmp[ 8 ] = {};
  143. detail::write64le( tmp, seed );
  144. update( tmp, 8 );
  145. result();
  146. update( tmp, 0 ); // sets finalized_ to false
  147. }
  148. }
  149. BOOST_HASH2_SHA3_CONSTEXPR sha3_256( unsigned char const * p, std::size_t n )
  150. {
  151. if( n != 0 )
  152. {
  153. update( p, n );
  154. result();
  155. update( p, 0 ); // sets finalized_ to false
  156. }
  157. }
  158. sha3_256( void const * p, std::size_t n ): sha3_256( static_cast<unsigned char const*>( p ), n )
  159. {
  160. }
  161. };
  162. class sha3_384: public detail::keccak_base<0x06, 2 * 384, 384>
  163. {
  164. public:
  165. BOOST_HASH2_SHA3_CONSTEXPR sha3_384()
  166. {
  167. }
  168. BOOST_HASH2_SHA3_CONSTEXPR explicit sha3_384( std::uint64_t seed )
  169. {
  170. if( seed != 0 )
  171. {
  172. unsigned char tmp[ 8 ] = {};
  173. detail::write64le( tmp, seed );
  174. update( tmp, 8 );
  175. result();
  176. update( tmp, 0 ); // sets finalized_ to false
  177. }
  178. }
  179. BOOST_HASH2_SHA3_CONSTEXPR sha3_384( unsigned char const * p, std::size_t n )
  180. {
  181. if( n != 0 )
  182. {
  183. update( p, n );
  184. result();
  185. update( p, 0 ); // sets finalized_ to false
  186. }
  187. }
  188. sha3_384( void const * p, std::size_t n ): sha3_384( static_cast<unsigned char const*>( p ), n )
  189. {
  190. }
  191. };
  192. class sha3_512: public detail::keccak_base<0x06, 2 * 512, 512>
  193. {
  194. public:
  195. BOOST_HASH2_SHA3_CONSTEXPR sha3_512()
  196. {
  197. }
  198. BOOST_HASH2_SHA3_CONSTEXPR explicit sha3_512( std::uint64_t seed )
  199. {
  200. if( seed != 0 )
  201. {
  202. unsigned char tmp[ 8 ] = {};
  203. detail::write64le( tmp, seed );
  204. update( tmp, 8 );
  205. result();
  206. update( tmp, 0 ); // sets finalized_ to false
  207. }
  208. }
  209. BOOST_HASH2_SHA3_CONSTEXPR sha3_512( unsigned char const * p, std::size_t n )
  210. {
  211. if( n != 0 )
  212. {
  213. update( p, n );
  214. result();
  215. update( p, 0 ); // sets finalized_ to false
  216. }
  217. }
  218. sha3_512( void const * p, std::size_t n ): sha3_512( static_cast<unsigned char const*>( p ), n )
  219. {
  220. }
  221. };
  222. class shake_128: public detail::keccak_base<0x1f, 256, 1600 - 256>
  223. {
  224. public:
  225. BOOST_HASH2_SHA3_CONSTEXPR shake_128()
  226. {
  227. }
  228. BOOST_HASH2_SHA3_CONSTEXPR explicit shake_128( std::uint64_t seed )
  229. {
  230. if( seed != 0 )
  231. {
  232. unsigned char tmp[ 8 ] = {};
  233. detail::write64le( tmp, seed );
  234. update( tmp, 8 );
  235. result();
  236. update( tmp, 0 ); // sets finalized_ to false
  237. }
  238. }
  239. BOOST_HASH2_SHA3_CONSTEXPR shake_128( unsigned char const * p, std::size_t n )
  240. {
  241. if( n != 0 )
  242. {
  243. update( p, n );
  244. result();
  245. update( p, 0 ); // sets finalized_ to false
  246. }
  247. }
  248. shake_128( void const * p, std::size_t n ): shake_128( static_cast<unsigned char const*>( p ), n )
  249. {
  250. }
  251. };
  252. class shake_256: public detail::keccak_base<0x1f, 512, 1600 - 512>
  253. {
  254. public:
  255. BOOST_HASH2_SHA3_CONSTEXPR shake_256()
  256. {
  257. }
  258. BOOST_HASH2_SHA3_CONSTEXPR explicit shake_256( std::uint64_t seed )
  259. {
  260. if( seed != 0 )
  261. {
  262. unsigned char tmp[ 8 ] = {};
  263. detail::write64le( tmp, seed );
  264. update( tmp, 8 );
  265. result();
  266. update( tmp, 0 ); // sets finalized_ to false
  267. }
  268. }
  269. BOOST_HASH2_SHA3_CONSTEXPR shake_256( unsigned char const * p, std::size_t n )
  270. {
  271. if( n != 0 )
  272. {
  273. update( p, n );
  274. result();
  275. update( p, 0 ); // sets finalized_ to false
  276. }
  277. }
  278. shake_256( void const * p, std::size_t n ): shake_256( static_cast<unsigned char const*>( p ), n )
  279. {
  280. }
  281. };
  282. using hmac_sha3_224 = hmac<sha3_224>;
  283. using hmac_sha3_256 = hmac<sha3_256>;
  284. using hmac_sha3_384 = hmac<sha3_384>;
  285. using hmac_sha3_512 = hmac<sha3_512>;
  286. } // namespace hash2
  287. } // namespace boost
  288. #endif // BOOST_HASH2_SHA3_HPP_INCLUDED