diff --git a/include/nil/crypto3/block/detail/serpent/serpent_functions.hpp b/include/nil/crypto3/block/detail/serpent/serpent_functions.hpp new file mode 100644 index 0000000..fb3fdab --- /dev/null +++ b/include/nil/crypto3/block/detail/serpent/serpent_functions.hpp @@ -0,0 +1,491 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_SERPENT_FUNCTIONS_CPP_HPP +#define CRYPTO3_SERPENT_FUNCTIONS_CPP_HPP + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace block { + namespace detail { + template + struct serpent_functions : public ::nil::crypto3::detail::basic_functions { + typedef ::nil::crypto3::detail::basic_functions policy_type; + typedef typename policy_type::word_type word_type; + + /* + * Serpent's Linear Transform + */ + inline static void transform(word_type &B0, word_type &B1, word_type &B2, word_type &B3) { + B0 = policy_type::rotl<13>(B0); + B2 = policy_type::rotl<3>(B2); + B1 ^= B0 ^ B2; + B3 ^= B2 ^ (B0 << 3); + B1 = policy_type::rotl<1>(B1); + B3 = policy_type::rotl<7>(B3); + B0 ^= B1 ^ B3; + B2 ^= B3 ^ (B1 << 7); + B0 = policy_type::rotl<5>(B0); + B2 = policy_type::rotl<22>(B2); + } + + /* + * Serpent's Inverse Linear Transform + */ + inline static void i_transform(word_type &B0, word_type &B1, word_type &B2, word_type &B3) { + B2 = policy_type::rotr<22>(B2); + B0 = policy_type::rotr<5>(B0); + B2 ^= B3 ^ (B1 << 7); + B0 ^= B1 ^ B3; + B3 = policy_type::rotr<7>(B3); + B1 = policy_type::rotr<1>(B1); + B3 ^= B2 ^ (B0 << 3); + B1 ^= B0 ^ B2; + B2 = policy_type::rotr<3>(B2); + B0 = policy_type::rotr<13>(B0); + } + }; + + /* + * Serpent SBox Expressions + * + * The sbox expressions used here were discovered by Dag Arne Osvik and + * are described in his paper "Speeding Up Serpent". + */ + +#define SBoxE1(B0, B1, B2, B3) \ + do { \ + B3 ^= B0; \ + auto B4 = B1; \ + B1 &= B3; \ + B4 ^= B2; \ + B1 ^= B0; \ + B0 |= B3; \ + B0 ^= B4; \ + B4 ^= B3; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 ^= B4; \ + B4 = ~B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B1 ^= B4; \ + B3 |= B0; \ + B1 ^= B3; \ + B4 ^= B3; \ + B3 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while (0) + +#define SBoxE2(B0, B1, B2, B3) \ + do { \ + B0 = ~B0; \ + B2 = ~B2; \ + auto B4 = B0; \ + B0 &= B1; \ + B2 ^= B0; \ + B0 |= B3; \ + B3 ^= B2; \ + B1 ^= B0; \ + B0 ^= B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B2 |= B0; \ + B2 &= B4; \ + B0 ^= B1; \ + B1 &= B2; \ + B1 ^= B0; \ + B0 &= B2; \ + B4 ^= B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B1; \ + B1 = B4; \ + } while (0) + +#define SBoxE3(B0, B1, B2, B3) \ + do { \ + auto B4 = B0; \ + B0 &= B2; \ + B0 ^= B3; \ + B2 ^= B1; \ + B2 ^= B0; \ + B3 |= B4; \ + B3 ^= B1; \ + B4 ^= B2; \ + B1 = B3; \ + B3 |= B4; \ + B3 ^= B0; \ + B0 &= B1; \ + B4 ^= B0; \ + B1 ^= B3; \ + B1 ^= B4; \ + B0 = B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = ~B4; \ + } while (0) + +#define SBoxE4(B0, B1, B2, B3) \ + do { \ + auto B4 = B0; \ + B0 |= B3; \ + B3 ^= B1; \ + B1 &= B4; \ + B4 ^= B2; \ + B2 ^= B3; \ + B3 &= B0; \ + B4 |= B1; \ + B3 ^= B4; \ + B0 ^= B1; \ + B4 &= B0; \ + B1 ^= B3; \ + B4 ^= B2; \ + B1 |= B0; \ + B1 ^= B2; \ + B0 ^= B3; \ + B2 = B1; \ + B1 |= B3; \ + B0 ^= B1; \ + B1 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while (0) + +#define SBoxE5(B0, B1, B2, B3) \ + do { \ + B1 ^= B3; \ + B3 = ~B3; \ + B2 ^= B3; \ + B3 ^= B0; \ + auto B4 = B1; \ + B1 &= B3; \ + B1 ^= B2; \ + B4 ^= B3; \ + B0 ^= B4; \ + B2 &= B4; \ + B2 ^= B0; \ + B0 &= B1; \ + B3 ^= B0; \ + B4 |= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B2 &= B3; \ + B0 = ~B0; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while (0) + +#define SBoxE6(B0, B1, B2, B3) \ + do { \ + B0 ^= B1; \ + B1 ^= B3; \ + B3 = ~B3; \ + auto B4 = B1; \ + B1 &= B0; \ + B2 ^= B3; \ + B1 ^= B2; \ + B2 |= B4; \ + B4 ^= B3; \ + B3 &= B1; \ + B3 ^= B0; \ + B4 ^= B1; \ + B4 ^= B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B2 = ~B2; \ + B0 ^= B4; \ + B4 |= B3; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B3; \ + B3 = B4; \ + } while (0) + +#define SBoxE7(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + auto B4 = B3; \ + B3 &= B0; \ + B0 ^= B4; \ + B3 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B2 ^= B0; \ + B0 |= B1; \ + B2 ^= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B4 ^= B3; \ + B4 ^= B0; \ + B3 = ~B3; \ + B2 &= B4; \ + B3 ^= B2; \ + B2 = B4; \ + } while (0) + +#define SBoxE8(B0, B1, B2, B3) \ + do { \ + auto B4 = B1; \ + B1 |= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B2 ^= B1; \ + B3 |= B4; \ + B3 &= B0; \ + B4 ^= B2; \ + B3 ^= B1; \ + B1 |= B4; \ + B1 ^= B0; \ + B0 |= B4; \ + B0 ^= B2; \ + B1 ^= B4; \ + B2 ^= B1; \ + B1 &= B0; \ + B1 ^= B4; \ + B2 = ~B2; \ + B2 |= B0; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = B0; \ + B0 = B4; \ + } while (0) + +#define SBoxD1(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + auto B4 = B1; \ + B1 |= B0; \ + B4 = ~B4; \ + B1 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B0 ^= B4; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 ^= B0; \ + B0 |= B1; \ + B0 ^= B2; \ + B3 ^= B4; \ + B2 ^= B1; \ + B3 ^= B0; \ + B3 ^= B1; \ + B2 &= B3; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B4; \ + } while (0) + +#define SBoxD2(B0, B1, B2, B3) \ + do { \ + auto B4 = B1; \ + B1 ^= B3; \ + B3 &= B1; \ + B4 ^= B2; \ + B3 ^= B0; \ + B0 |= B1; \ + B2 ^= B3; \ + B0 ^= B4; \ + B0 |= B2; \ + B1 ^= B3; \ + B0 ^= B1; \ + B1 |= B3; \ + B1 ^= B0; \ + B4 = ~B4; \ + B4 ^= B1; \ + B1 |= B0; \ + B1 ^= B0; \ + B1 |= B4; \ + B3 ^= B1; \ + B1 = B0; \ + B0 = B4; \ + B4 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while (0) + +#define SBoxD3(B0, B1, B2, B3) \ + do { \ + B2 ^= B3; \ + B3 ^= B0; \ + auto B4 = B3; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 |= B2; \ + B1 ^= B4; \ + B4 &= B3; \ + B2 ^= B3; \ + B4 &= B0; \ + B4 ^= B2; \ + B2 &= B1; \ + B2 |= B0; \ + B3 = ~B3; \ + B2 ^= B3; \ + B0 ^= B3; \ + B0 &= B1; \ + B3 ^= B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + } while (0) + +#define SBoxD4(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 ^= B1; \ + B0 ^= B2; \ + B4 &= B2; \ + B4 ^= B0; \ + B0 &= B1; \ + B1 ^= B3; \ + B3 |= B4; \ + B2 ^= B3; \ + B0 ^= B3; \ + B1 ^= B4; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 ^= B0; \ + B1 |= B2; \ + B0 ^= B3; \ + B1 ^= B4; \ + B0 ^= B1; \ + B4 = B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while (0) + +#define SBoxD5(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 &= B3; \ + B2 ^= B1; \ + B1 |= B3; \ + B1 &= B0; \ + B4 ^= B2; \ + B4 ^= B1; \ + B1 &= B2; \ + B0 = ~B0; \ + B3 ^= B4; \ + B1 ^= B3; \ + B3 &= B0; \ + B3 ^= B2; \ + B0 ^= B1; \ + B2 &= B0; \ + B3 ^= B0; \ + B2 ^= B4; \ + B2 |= B3; \ + B3 ^= B0; \ + B2 ^= B1; \ + B1 = B3; \ + B3 = B4; \ + } while (0) + +#define SBoxD6(B0, B1, B2, B3) \ + do { \ + B1 = ~B1; \ + auto B4 = B3; \ + B2 ^= B1; \ + B3 |= B0; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 ^= B4; \ + B4 |= B0; \ + B4 ^= B1; \ + B1 &= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B3 &= B4; \ + B4 ^= B1; \ + B3 ^= B4; \ + B4 = ~B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + B4 = B3; \ + B3 = B2; \ + B2 = B4; \ + } while (0) + +#define SBoxD7(B0, B1, B2, B3) \ + do { \ + B0 ^= B2; \ + auto B4 = B2; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B2 ^= B3; \ + B4 |= B0; \ + B0 ^= B2; \ + B3 ^= B4; \ + B4 ^= B1; \ + B1 &= B3; \ + B1 ^= B0; \ + B0 ^= B3; \ + B0 |= B2; \ + B3 ^= B1; \ + B4 ^= B0; \ + B0 = B1; \ + B1 = B2; \ + B2 = B4; \ + } while (0) + +#define SBoxD8(B0, B1, B2, B3) \ + do { \ + auto B4 = B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 |= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B1 |= B0; \ + B0 ^= B2; \ + B2 &= B4; \ + B3 &= B4; \ + B1 ^= B2; \ + B2 ^= B0; \ + B0 |= B2; \ + B4 ^= B1; \ + B0 ^= B3; \ + B3 ^= B4; \ + B4 |= B0; \ + B3 ^= B2; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B0; \ + B0 = B3; \ + B3 = B4; \ + } while (0) +/* + * XOR a key block with a data block + */ +#define key_xor(round, B0, B1, B2, B3) \ + B0 ^= key_schedule[4 * round]; \ + B1 ^= key_schedule[4 * round + 1]; \ + B2 ^= key_schedule[4 * round + 2]; \ + B3 ^= key_schedule[4 * round + 3]; + } // namespace detail + } // namespace block + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_SERPENT_FUNCTIONS_CPP_HPP diff --git a/include/nil/crypto3/block/detail/serpent/serpent_policy.hpp b/include/nil/crypto3/block/detail/serpent/serpent_policy.hpp new file mode 100644 index 0000000..8764410 --- /dev/null +++ b/include/nil/crypto3/block/detail/serpent/serpent_policy.hpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLOCK_DETAIL_SERPENT_POLICY_HPP +#define CRYPTO3_BLOCK_DETAIL_SERPENT_POLICY_HPP + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace block { + namespace detail { + + template + struct basic_serpent_policy : serpent_functions<32> { + constexpr static const std::size_t rounds = 32; + + constexpr static const std::size_t block_bits = 128; + constexpr static const std::size_t block_words = block_bits / word_bits; + typedef std::array block_type; + + constexpr static const std::size_t key_bits = Version; + constexpr static const std::size_t key_words = key_bits / word_bits; + typedef std::array key_type; + typedef std::array key_schedule_type; + + constexpr static const std::size_t tweak_bits = 128; + constexpr static const std::size_t tweak_words = tweak_bits / word_bits; + typedef std::array tweak_type; + typedef std::array tweak_schedule_type; + + typedef std::array permutations_type; + typedef std::array, 8> rotations_type; + + constexpr static const word_type phi = 0x9E3779B9; + }; + + template + struct serpent_policy; + + template<> + struct serpent_policy<128> : basic_serpent_policy<128> { + typedef std::array constants_type; + }; + + template<> + struct serpent_policy<192> : basic_serpent_policy<192> { + typedef std::array constants_type; + }; + + template<> + struct serpent_policy<256> : basic_serpent_policy<256> { + typedef std::array constants_type; + }; + + } // namespace detail + } // namespace block + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_BLOCK_DETAIL_SERPENT_POLICY_HPP diff --git a/include/nil/crypto3/block/serpent.hpp b/include/nil/crypto3/block/serpent.hpp new file mode 100644 index 0000000..4070bcd --- /dev/null +++ b/include/nil/crypto3/block/serpent.hpp @@ -0,0 +1,362 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// Copyright (c) 2020 Nikita Kaskov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLOCK_SERPENT_HPP +#define CRYPTO3_BLOCK_SERPENT_HPP + +#include +#include + +#include + +#include +#include + +namespace nil { + namespace crypto3 { + namespace block { + /*! + * @brief Serpent. The most conservative of the AES finalists + * https://www.cl.cam.ac.uk/~rja14/serpent.html. An AES contender. + * Widely considered the most conservative design. Fairly slow, + * especially if no SIMD instruction set is available. + * + * @ingroup block + * @tparam KeyBits Block cipher key bits. Available values are: 128, 192, 256 + */ + template + class serpent { + protected: + typedef detail::serpent_policy policy_type; + + constexpr static const std::size_t key_schedule_size = policy_type::key_schedule_size; + typedef typename policy_type::key_schedule_type key_schedule_type; + + public: + constexpr static const std::size_t rounds = policy_type::rounds; + + constexpr static const std::size_t word_bits = policy_type::word_bits; + typedef typename policy_type::word_type word_type; + + constexpr static const std::size_t block_bits = policy_type::block_bits; + constexpr static const std::size_t block_words = policy_type::block_words; + typedef typename policy_type::block_type block_type; + + constexpr static const std::size_t key_bits = policy_type::key_bits; + constexpr static const std::size_t key_words = policy_type::key_words; + typedef typename policy_type::key_type key_type; + + serpent(const key_type &key) { + schedule_key(key); + } + + ~serpent() { + key_schedule.fill(0); + } + + inline block_type encrypt(const block_type &plaintext) const { + return encrypt_block(plaintext); + } + + inline block_type decrypt(const block_type &ciphertext) const { + return decrypt_block(ciphertext); + } + + template + struct stream_processor { + struct params_type { + + constexpr static const std::size_t value_bits = ValueBits; + constexpr static const std::size_t length_bits = policy_type::word_bits * 2; + }; + + typedef block_stream_processor type; + }; + + typedef typename stream_endian::little_octet_big_bit endian_type; + protected: + key_schedule_type key_schedule; + + inline block_type encrypt_block(const block_type &plaintext) const { + word_type B0 = boost::endian::native_to_little(plaintext[0]); + word_type B1 = boost::endian::native_to_little(plaintext[1]); + word_type B2 = boost::endian::native_to_little(plaintext[2]); + word_type B3 = boost::endian::native_to_little(plaintext[3]); + + key_xor(0, B0, B1, B2, B3); + SBoxE1(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(1, B0, B1, B2, B3); + SBoxE2(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(2, B0, B1, B2, B3); + SBoxE3(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(3, B0, B1, B2, B3); + SBoxE4(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(4, B0, B1, B2, B3); + SBoxE5(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(5, B0, B1, B2, B3); + SBoxE6(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(6, B0, B1, B2, B3); + SBoxE7(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(7, B0, B1, B2, B3); + SBoxE8(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(8, B0, B1, B2, B3); + SBoxE1(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(9, B0, B1, B2, B3); + SBoxE2(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(10, B0, B1, B2, B3); + SBoxE3(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(11, B0, B1, B2, B3); + SBoxE4(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(12, B0, B1, B2, B3); + SBoxE5(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(13, B0, B1, B2, B3); + SBoxE6(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(14, B0, B1, B2, B3); + SBoxE7(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(15, B0, B1, B2, B3); + SBoxE8(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(16, B0, B1, B2, B3); + SBoxE1(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(17, B0, B1, B2, B3); + SBoxE2(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(18, B0, B1, B2, B3); + SBoxE3(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(19, B0, B1, B2, B3); + SBoxE4(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(20, B0, B1, B2, B3); + SBoxE5(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(21, B0, B1, B2, B3); + SBoxE6(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(22, B0, B1, B2, B3); + SBoxE7(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(23, B0, B1, B2, B3); + SBoxE8(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(24, B0, B1, B2, B3); + SBoxE1(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(25, B0, B1, B2, B3); + SBoxE2(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(26, B0, B1, B2, B3); + SBoxE3(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(27, B0, B1, B2, B3); + SBoxE4(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(28, B0, B1, B2, B3); + SBoxE5(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(29, B0, B1, B2, B3); + SBoxE6(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(30, B0, B1, B2, B3); + SBoxE7(B0, B1, B2, B3); + policy_type::transform(B0, B1, B2, B3); + key_xor(31, B0, B1, B2, B3); + SBoxE8(B0, B1, B2, B3); + key_xor(32, B0, B1, B2, B3); + + return {boost::endian::little_to_native(B0), boost::endian::little_to_native(B1), + boost::endian::little_to_native(B2), boost::endian::little_to_native(B3)}; + } + + inline block_type decrypt_block(const block_type &ciphertext) const { + word_type B0 = ciphertext[0]; + word_type B1 = ciphertext[1]; + word_type B2 = ciphertext[2]; + word_type B3 = ciphertext[3]; + + key_xor(32, B0, B1, B2, B3); + SBoxD8(B0, B1, B2, B3); + key_xor(31, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD7(B0, B1, B2, B3); + key_xor(30, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD6(B0, B1, B2, B3); + key_xor(29, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD5(B0, B1, B2, B3); + key_xor(28, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD4(B0, B1, B2, B3); + key_xor(27, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD3(B0, B1, B2, B3); + key_xor(26, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD2(B0, B1, B2, B3); + key_xor(25, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD1(B0, B1, B2, B3); + key_xor(24, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD8(B0, B1, B2, B3); + key_xor(23, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD7(B0, B1, B2, B3); + key_xor(22, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD6(B0, B1, B2, B3); + key_xor(21, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD5(B0, B1, B2, B3); + key_xor(20, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD4(B0, B1, B2, B3); + key_xor(19, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD3(B0, B1, B2, B3); + key_xor(18, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD2(B0, B1, B2, B3); + key_xor(17, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD1(B0, B1, B2, B3); + key_xor(16, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD8(B0, B1, B2, B3); + key_xor(15, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD7(B0, B1, B2, B3); + key_xor(14, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD6(B0, B1, B2, B3); + key_xor(13, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD5(B0, B1, B2, B3); + key_xor(12, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD4(B0, B1, B2, B3); + key_xor(11, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD3(B0, B1, B2, B3); + key_xor(10, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD2(B0, B1, B2, B3); + key_xor(9, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD1(B0, B1, B2, B3); + key_xor(8, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD8(B0, B1, B2, B3); + key_xor(7, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD7(B0, B1, B2, B3); + key_xor(6, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD6(B0, B1, B2, B3); + key_xor(5, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD5(B0, B1, B2, B3); + key_xor(4, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD4(B0, B1, B2, B3); + key_xor(3, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD3(B0, B1, B2, B3); + key_xor(2, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD2(B0, B1, B2, B3); + key_xor(1, B0, B1, B2, B3); + policy_type::i_transform(B0, B1, B2, B3); + SBoxD1(B0, B1, B2, B3); + key_xor(0, B0, B1, B2, B3); + + return {boost::endian::little_to_native(B0), boost::endian::little_to_native(B1), + boost::endian::little_to_native(B2), boost::endian::little_to_native(B3)}; + } + + void schedule_key(const key_type &key) { + std::array W = {0}; + for (size_t i = 0; i != key.size() / 4; ++i) { + W[i] = boost::endian::native_to_little(key[i]); + } + + W[key.size() / 4] |= word_type(1) << ((key.size() % 4) * 8); + + for (size_t i = 8; i != 140; ++i) { + word_type wi = W[i - 8] ^ W[i - 5] ^ W[i - 3] ^ W[i - 1] ^ policy_type::phi ^ word_type(i - 8); + W[i] = policy_type::template rotl<11>(wi); + } + + SBoxE1(W[20], W[21], W[22], W[23]); + SBoxE1(W[52], W[53], W[54], W[55]); + SBoxE1(W[84], W[85], W[86], W[87]); + SBoxE1(W[116], W[117], W[118], W[119]); + + SBoxE2(W[16], W[17], W[18], W[19]); + SBoxE2(W[48], W[49], W[50], W[51]); + SBoxE2(W[80], W[81], W[82], W[83]); + SBoxE2(W[112], W[113], W[114], W[115]); + + SBoxE3(W[12], W[13], W[14], W[15]); + SBoxE3(W[44], W[45], W[46], W[47]); + SBoxE3(W[76], W[77], W[78], W[79]); + SBoxE3(W[108], W[109], W[110], W[111]); + + SBoxE4(W[8], W[9], W[10], W[11]); + SBoxE4(W[40], W[41], W[42], W[43]); + SBoxE4(W[72], W[73], W[74], W[75]); + SBoxE4(W[104], W[105], W[106], W[107]); + SBoxE4(W[136], W[137], W[138], W[139]); + + SBoxE5(W[36], W[37], W[38], W[39]); + SBoxE5(W[68], W[69], W[70], W[71]); + SBoxE5(W[100], W[101], W[102], W[103]); + SBoxE5(W[132], W[133], W[134], W[135]); + + SBoxE6(W[32], W[33], W[34], W[35]); + SBoxE6(W[64], W[65], W[66], W[67]); + SBoxE6(W[96], W[97], W[98], W[99]); + SBoxE6(W[128], W[129], W[130], W[131]); + + SBoxE7(W[28], W[29], W[30], W[31]); + SBoxE7(W[60], W[61], W[62], W[63]); + SBoxE7(W[92], W[93], W[94], W[95]); + SBoxE7(W[124], W[125], W[126], W[127]); + + SBoxE8(W[24], W[25], W[26], W[27]); + SBoxE8(W[56], W[57], W[58], W[59]); + SBoxE8(W[88], W[89], W[90], W[91]); + SBoxE8(W[120], W[121], W[122], W[123]); + + key_schedule.assign(W.begin() + 8, W.end()); + + W.fill(0); + } + }; + } // namespace block + } // namespace crypto3 +} // namespace nil +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6e6c334..9dd3cd9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,6 +41,7 @@ set(TESTS_NAMES "rijndael" "md4" "md5" + "serpent" "shacal" "shacal2" ) diff --git a/test/serpent.cpp b/test/serpent.cpp new file mode 100644 index 0000000..5fdc577 --- /dev/null +++ b/test/serpent.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2018-2020 Mikhail Komarov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE serpent_cipher_test + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace nil::crypto3::block; + +namespace boost { + namespace test_tools { + namespace tt_detail { + template class P, typename K, typename V> + struct print_log_value> { + void operator()(std::ostream&, P const&) { + } + }; + } // namespace tt_detail + } // namespace test_tools +} // namespace boost + +static const std::unordered_map> valid_data = { + {"Zg==", {0x66}}, + {"Zm8=", {0x66, 0x6F}}, + {"Zm9v", {0x66, 0x6F, 0x6F}}, + {"aGVsbG8gd29ybGQ=", {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64}}, + {"aGVsbG8gd29ybGQh", {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21}}, + {"SGVsbG8sIHdvcmxkLg==", {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x2E}}, + {"VGhlIDEyIGNoYXJz", {0x54, 0x68, 0x65, 0x20, 0x31, 0x32, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73}}, + {"VGhlIDEzIGNoYXJzLg==", {0x54, 0x68, 0x65, 0x20, 0x31, 0x33, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E}}, + {"VGhlIDE0IGNoYXJzLi4=", {0x54, 0x68, 0x65, 0x20, 0x31, 0x34, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E, 0x2E}}, + {"VGhlIDE1IGNoYXJzLi4u", + {0x54, 0x68, 0x65, 0x20, 0x31, 0x35, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x2E, 0x2E, 0x2E}}, + {"QW4gVVRGLTggdXVtbDogw7w=", + {0x41, 0x6E, 0x20, 0x55, 0x54, 0x46, 0x2D, 0x38, 0x20, 0x75, 0x75, 0x6D, 0x6C, 0x3A, 0x20, 0xC3, 0xBC}}, + {"V2VpcmQgR2VybWFuIDIgYnl0ZSB0aGluZzogw58u", + {0x57, 0x65, 0x69, 0x72, 0x64, 0x20, 0x47, 0x65, 0x72, 0x6D, 0x61, 0x6E, 0x20, 0x32, 0x20, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0xC3, 0x9F, 0x2E}}, + {"mw==", {0x9B}}, + {"HGA=", {0x1C, 0x60}}, + {"gTS9", {0x81, 0x34, 0xBD}}, + {"Xmz/3g==", {0x5E, 0x6C, 0xFF, 0xDE}}, + {"ss3w3H8=", {0xb2, 0xcd, 0xf0, 0xdc, 0x7f}}, + {"/FYt2tQO", {0xfc, 0x56, 0x2d, 0xda, 0xd4, 0x0e}}, + {"KbIyLohB6A==", {0x29, 0xb2, 0x32, 0x2e, 0x88, 0x41, 0xe8}}, + {"Dw/O2Ul6r5I=", {0x0f, 0x0f, 0xce, 0xd9, 0x49, 0x7a, 0xaf, 0x92}}, + {"Jw+xiYKADaZA", {0x27, 0x0f, 0xb1, 0x89, 0x82, 0x80, 0x0d, 0xa6, 0x40}}}; + +static const std::vector invalid_data = {"ZOOL!isnotvalidbase64", "Neitheris:this?"}; + +BOOST_AUTO_TEST_SUITE(serpent_encode_test_suite) + +BOOST_DATA_TEST_CASE(serpent_single_range_encode, boost::unit_test::data::make(valid_data), array_element) { +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file