libcruft-crypto/block/speck.cpp

109 lines
2.3 KiB
C++

/*
* 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;
}
///////////////////////////////////////////////////////////////////////////////
speck::block_t
speck::encrypt (block_t 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 (block_t 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 };
}