#ifndef BOOST_UUID_DETAIL_CHACHA20_HPP_INCLUDED #define BOOST_UUID_DETAIL_CHACHA20_HPP_INCLUDED // Copyright 2024 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #include #include namespace boost { namespace uuids { namespace detail { class chacha20_12 { private: std::uint32_t state_[ 16 ]; std::uint32_t block_[ 16 ]; std::size_t index_; private: static inline std::uint32_t rotl( std::uint32_t x, int n ) noexcept { return ( x << n ) | ( x >> (32 - n) ); } static inline void quarter_round( std::uint32_t (&x)[ 16 ], int a, int b, int c, int d ) noexcept { x[ a ] += x[ b ]; x[ d ] = rotl( x[d] ^ x[a], 16 ); x[ c ] += x[ d ]; x[ b ] = rotl( x[b] ^ x[c], 12 ); x[ a ] += x[ b ]; x[ d ] = rotl( x[d] ^ x[a], 8 ); x[ c ] += x[ d ]; x[ b ] = rotl( x[b] ^ x[c], 7 ); } void get_next_block() noexcept { for( int i = 0; i < 16; ++i ) { block_[ i ] = state_[ i ]; } for( int i = 0; i < 6; ++i ) { quarter_round( block_, 0, 4, 8, 12 ); quarter_round( block_, 1, 5, 9, 13 ); quarter_round( block_, 2, 6, 10, 14 ); quarter_round( block_, 3, 7, 11, 15 ); quarter_round( block_, 0, 5, 10, 15 ); quarter_round( block_, 1, 6, 11, 12 ); quarter_round( block_, 2, 7, 8, 13 ); quarter_round( block_, 3, 4, 9, 14 ); } for( int i = 0; i < 16; ++i ) { block_[ i ] += state_[ i ]; } if( ++state_[ 12 ] == 0 ) ++state_[ 13 ]; } public: using result_type = std::uint32_t; chacha20_12() noexcept: index_( 16 ) { state_[ 0 ] = 0x61707865; state_[ 1 ] = 0x3320646e; state_[ 2 ] = 0x79622d32; state_[ 3 ] = 0x6b206574; for( int i = 4; i < 16; ++i ) { state_[ i ] = 0; } } chacha20_12( std::uint32_t const (&key)[ 8 ], std::uint32_t const (&nonce)[ 2 ] ) noexcept: index_( 16 ) { state_[ 0 ] = 0x61707865; state_[ 1 ] = 0x3320646e; state_[ 2 ] = 0x79622d32; state_[ 3 ] = 0x6b206574; for( int i = 0; i < 8; ++i ) { state_[ i + 4 ] = key[ i ]; } state_[ 12 ] = 0; state_[ 13 ] = 0; state_[ 14 ] = nonce[ 0 ]; state_[ 15 ] = nonce[ 1 ]; } // only needed because basic_random_generator looks for it void seed() noexcept { index_ = 16; for( int i = 4; i < 16; ++i ) { state_[ i ] = 0; } } template void seed( Seq& seq ) { index_ = 16; seq.generate( state_ + 4, state_ + 16 ); // reset counter state_[ 12 ] = 0; state_[ 13 ] = 0; } // perturbs the generator state so that it no longer generates // the same sequence; useful for e.g. moved from objects void perturb() noexcept { index_ = 16; for( int i = 12; i < 16; ++i ) { ++state_[ i ]; } } static constexpr result_type min() noexcept { return std::numeric_limits::min(); } static constexpr result_type max() noexcept { return std::numeric_limits::max(); } result_type operator()() noexcept { if( index_ == 16 ) { get_next_block(); index_ = 0; } return block_[ index_++ ]; } }; }}} // namespace boost::uuids::detail #endif // #ifndef BOOST_UUID_DETAIL_SHA1_HPP_INCLUDED