diff options
author | Jack Lloyd <[email protected]> | 2018-12-08 09:01:22 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-12-08 09:01:22 -0500 |
commit | 06d67fe7e072ab760e8c97c515610343672dd58f (patch) | |
tree | d52064b0c8296c3e6a594c7e79602fbca83bf696 /src/lib | |
parent | 9e81ecff2d853eb644ca98fa9f37fcb9f4ef10d4 (diff) | |
parent | 3a4790b639cf4aa4701725653bcaaa25cee78100 (diff) |
Merge GH #1775 Clean up Streebog and fix unaligned loads
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/hash/streebog/streebog.cpp | 206 | ||||
-rw-r--r-- | src/lib/hash/streebog/streebog.h | 2 |
2 files changed, 114 insertions, 94 deletions
diff --git a/src/lib/hash/streebog/streebog.cpp b/src/lib/hash/streebog/streebog.cpp index 8bb56ccc9..c92e1123f 100644 --- a/src/lib/hash/streebog/streebog.cpp +++ b/src/lib/hash/streebog/streebog.cpp @@ -1,6 +1,7 @@ /* * Streebog * (C) 2017 Ribose Inc. +* (C) 2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -18,89 +19,6 @@ std::unique_ptr<HashFunction> Streebog::copy_state() const return std::unique_ptr<HashFunction>(new Streebog(*this)); } -namespace { - -static inline void addm(const uint8_t* m, uint64_t* h) - { - uint64_t carry = false; - for(int i = 0; i < 8; i++) - { - const uint64_t m64 = load_le<uint64_t>(m, i); - const uint64_t hi = load_le<uint64_t>(reinterpret_cast<uint8_t*>(h), i); - const uint64_t t = hi + m64; - - const uint64_t overflow = (t < hi ? 1 : 0) | (t < m64 ? 1 : 0); - store_le(t + carry, reinterpret_cast<uint8_t*>(&h[i])); - carry = overflow; - } - } - -inline void lps(uint64_t block[8]) - { - uint8_t r[64]; - // FIXME - std::memcpy(r, block, 64); - - for(int i = 0; i < 8; ++i) - { - block[i] = load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[0][r[i]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[1][r[i + 8]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[2][r[i + 16]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[3][r[i + 24]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[4][r[i + 32]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[5][r[i + 40]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[6][r[i + 48]]), 0) ^ - load_le<uint64_t>(reinterpret_cast<const uint8_t*>(&STREEBOG_Ax[7][r[i + 56]]), 0); - } - } - -inline void e(uint64_t* K, const uint64_t* m) - { - uint64_t A[8]; - uint64_t C[8]; - - copy_mem(A, K, 8); - - for(size_t i = 0; i != 8; ++i) - { - K[i] ^= m[i]; - } - - for(size_t i = 0; i < 12; ++i) - { - lps(K); - load_le(C, reinterpret_cast<const uint8_t*>(&STREEBOG_C[i][0]), 8); - - for(size_t j = 0; j != 8; ++j) - A[j] ^= C[j]; - lps(A); - for(size_t j = 0; j != 8; ++j) - K[j] ^= A[j]; - } - } - -inline void g(uint64_t* h, const uint8_t* m, uint64_t N) - { - uint64_t hN[8]; - - // force N to little-endian - store_le(N, reinterpret_cast<uint8_t*>(&N)); - - copy_mem(hN, h, 8); - hN[0] ^= N; - lps(hN); - const uint64_t* m64 = reinterpret_cast<const uint64_t*>(m); - - e(hN, m64); - - for(size_t i = 0; i != 8; ++i) - { - h[i] ^= hN[i] ^ m64[i]; - } - } - -} //namespace - Streebog::Streebog(size_t output_bits) : m_output_bits(output_bits), m_count(0), @@ -140,18 +58,33 @@ void Streebog::clear() */ void Streebog::add_data(const uint8_t input[], size_t length) { - while(m_position + length >= 64) + const size_t block_size = m_buffer.size(); + + if(m_position) { - buffer_insert(m_buffer, m_position, input, 64 - m_position); - compress(m_buffer.data()); + buffer_insert(m_buffer, m_position, input, length); + + if(m_position + length >= block_size) + { + compress(m_buffer.data()); + m_count += 512; + input += (block_size - m_position); + length -= (block_size - m_position); + m_position = 0; + } + } + + const size_t full_blocks = length / block_size; + const size_t remaining = length % block_size; + + for(size_t i = 0; i != full_blocks; ++i) + { + compress(input + block_size * i); m_count += 512; - input += (64 - m_position); - length -= (64 - m_position); - m_position = 0; } - buffer_insert(m_buffer, m_position, input, length); - m_position += length; + buffer_insert(m_buffer, m_position, input + full_blocks * block_size, remaining); + m_position += remaining; } /* @@ -171,17 +104,102 @@ void Streebog::final_result(uint8_t output[]) store_le(m_count, m_buffer.data()); compress(m_buffer.data(), true); - compress(reinterpret_cast<const uint8_t*>(m_S.data()), true); + compress_64(m_S.data(), true); // FIXME std::memcpy(output, &m_h[8 - output_length() / 8], output_length()); clear(); } +namespace { + +inline uint64_t force_le(uint64_t x) + { +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + return x; +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + return reverse_bytes(x); +#else + store_le(x, reinterpret_cast<uint8_t*>(&x)); + return x; +#endif + } + +inline void lps(uint64_t block[8]) + { + uint8_t r[64]; + // FIXME + std::memcpy(r, block, 64); + + for(int i = 0; i < 8; ++i) + { + block[i] = force_le(STREEBOG_Ax[0][r[i + 0*8]]) ^ + force_le(STREEBOG_Ax[1][r[i + 1*8]]) ^ + force_le(STREEBOG_Ax[2][r[i + 2*8]]) ^ + force_le(STREEBOG_Ax[3][r[i + 3*8]]) ^ + force_le(STREEBOG_Ax[4][r[i + 4*8]]) ^ + force_le(STREEBOG_Ax[5][r[i + 5*8]]) ^ + force_le(STREEBOG_Ax[6][r[i + 6*8]]) ^ + force_le(STREEBOG_Ax[7][r[i + 7*8]]); + } + } + +} //namespace + void Streebog::compress(const uint8_t input[], bool last_block) { - g(m_h.data(), input, last_block ? 0ULL : m_count); + uint64_t M[8]; + std::memcpy(M, input, 64); + + compress_64(M, last_block); + } + +void Streebog::compress_64(const uint64_t M[], bool last_block) + { + uint64_t N = force_le(last_block ? 0ULL : m_count); + + uint64_t hN[8]; + uint64_t A[8]; + + copy_mem(hN, m_h.data(), 8); + hN[0] ^= N; + lps(hN); + + copy_mem(A, hN, 8); + + for(size_t i = 0; i != 8; ++i) + { + hN[i] ^= M[i]; + } + + for(size_t i = 0; i < 12; ++i) + { + for(size_t j = 0; j != 8; ++j) + A[j] ^= force_le(STREEBOG_C[i][j]); + lps(A); + + lps(hN); + for(size_t j = 0; j != 8; ++j) + hN[j] ^= A[j]; + } + + for(size_t i = 0; i != 8; ++i) + { + m_h[i] ^= hN[i] ^ M[i]; + } + if(!last_block) - { addm(input, m_S.data()); } + { + uint64_t carry = 0; + for(int i = 0; i < 8; i++) + { + const uint64_t m = force_le(M[i]); + const uint64_t hi = force_le(m_S[i]); + const uint64_t t = hi + m; + + m_S[i] = force_le(t + carry); + carry = (t < hi ? 1 : 0) | (t < m ? 1 : 0); + } + } } } diff --git a/src/lib/hash/streebog/streebog.h b/src/lib/hash/streebog/streebog.h index 70e38733f..2c5928d0e 100644 --- a/src/lib/hash/streebog/streebog.h +++ b/src/lib/hash/streebog/streebog.h @@ -35,6 +35,8 @@ class BOTAN_PUBLIC_API(2,2) Streebog : public HashFunction void compress(const uint8_t input[], bool lastblock = false); + void compress_64(const uint64_t input[], bool lastblock = false); + private: const size_t m_output_bits; uint64_t m_count; |