block: add initial speck implementation

This commit is contained in:
Danny Robson 2018-12-02 18:17:19 +11:00
parent 0f12e8a87c
commit 8c21600805
4 changed files with 175 additions and 0 deletions

View File

@ -47,6 +47,8 @@ list (APPEND sources
stream/salsa.cpp
stream/salsa.hpp
block/speck.hpp
block/speck.cpp
block/tea.cpp
block/tea.hpp
block/xtea.cpp
@ -79,6 +81,7 @@ if (TESTS)
stream/rc4
stream/salsa
block/speck
block/tea
block/xtea
block/xxtea

108
block/speck.cpp Normal file
View File

@ -0,0 +1,108 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "speck.hpp"
#include <cruft/util/bitwise.hpp>
using cruft::crypto::block::speck;
///////////////////////////////////////////////////////////////////////////////
/// The round function for the encryption direction.
///
/// Mutates the x and y values.
///
/// \param x first data word
/// \param y second data word
/// \param k key word
static void
round_enc (u64 &x, u64 &y, u64 const &k)
{
x = cruft::rotater (x, 8);
x += y;
x ^= k;
y = cruft::rotatel (y, 3);
y ^= x;
}
///----------------------------------------------------------------------------
/// The round function for the decryption direction
///
/// Mutates the x and y values.
///
/// \param x
/// \param y
/// \param k
static void
round_dec (u64 &x, u64 &y, u64 const &k)
{
y ^= x;
y = cruft::rotater (y, 3);
x ^= k;
x -= y;
x = cruft::rotatel (x, 8);
}
///////////////////////////////////////////////////////////////////////////////
/// Initialise the key schedule
speck::speck (std::array<u64,2> _key)
{
auto &x = _key[0];
auto &y = _key[1];
// Allocate a space to store the schedule as it's computed
std::array<u64,32> schedule;
schedule[0] = y;
// Initialise the key to be indices 0..31
std::iota (std::begin (m_key), std::end (m_key), 0);
// 'encrypt' the key using the index schedule
for (int i = 0; i < 31; ++i) {
round_enc (x, y, m_key[i]);
schedule[i + 1] = y;
}
// Copy the computed schedule back out
m_key = schedule;
}
///////////////////////////////////////////////////////////////////////////////
std::array<u64,2>
speck::encrypt (std::array<u64,2> plaintext) const
{
u64 &x = plaintext[0];
u64 &y = plaintext[1];
for (int i = 0; i < 32; i++)
round_enc (x, y, m_key[i]);
return { x, y };
}
//-----------------------------------------------------------------------------
std::array<u64,2>
speck::decrypt (std::array<u64,2> plaintext) const
{
u64 &x = plaintext[0];
u64 &y = plaintext[1];
for (int i = 0; i < 32; i++)
round_dec (x, y, m_key[31 - i]);
return { x, y };
}

41
block/speck.hpp Normal file
View File

@ -0,0 +1,41 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <cstddef>
#include <array>
#include <cruft/util/std.hpp>
#include <cruft/util/view.hpp>
namespace cruft::crypto::block {
//template <
// std::size_t KeyBitsV,
// std::size_t BlockBitsV
//>
/// An implementation of the Speck block cipher.
/// doi: 10.1145/2744769.2747946
///
/// TODO: The block and key sizes are currently hard coded to 128 and 128
/// for ease of initial implementation. They should be parameters.
class speck {
public:
using key_t = std::array<u64,2>;
using word_t = u64;
static constexpr auto block_size = sizeof (word_t) * 2;
explicit speck (key_t);
std::array<word_t,2> encrypt (std::array<word_t,2> src) const;
std::array<word_t,2> decrypt (std::array<word_t,2> src) const;
private:
std::array<u64,32> m_key;
};
}

23
test/block/speck.cpp Normal file
View File

@ -0,0 +1,23 @@
#include <cruft/util/tap.hpp>
#include "block/speck.hpp"
int
main (void)
{
cruft::TAP::logger tap;
{
// speck128/128 test vectors from the IACR paper.
std::array<u64,2> const key { 0x0f0e0d0c0b0a0908, 0x0706050403020100 };
std::array<u64,2> const dec { 0x6c61766975716520, 0x7469206564616d20 };
std::array<u64,2> const enc { 0xa65d985179783265, 0x7860fedf5c570d18 };
cruft::crypto::block::speck const cipher (key);
tap.expect (cipher.encrypt (dec) == enc, "speck128/128 encode");
tap.expect (cipher.decrypt (enc) == dec, "speck128/128 decode");
}
return tap.status ();
}