aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/hash
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-12-07 17:24:36 -0500
committerJack Lloyd <[email protected]>2018-12-08 06:43:39 -0500
commit3a4790b639cf4aa4701725653bcaaa25cee78100 (patch)
treed42b4bb4380f1bfc5a14b507b037696f3bf53e66 /src/lib/hash
parent1605c244695a9d2b871dc46c8dbe6bc3fced45a6 (diff)
Clean up Streebog and fix use of unaligned loads
Diffstat (limited to 'src/lib/hash')
-rw-r--r--src/lib/hash/streebog/streebog.cpp206
-rw-r--r--src/lib/hash/streebog/streebog.h2
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;