Welcome to Code Forum!

Join a community that supports you and your coding journey from day one. We strive to be a friendly, supportive community that empowers everyone to be better developers. By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.

    GIF shows where to locate </> in the thread and or post editor toolbar.
    To learn more about how to use our BBCode feature, review our "How to post your code into threads" here.

    Thank you, Code Forum.

C++ full SERPENT cipher implementation tutorial

since im new here, i will share this c++ code which is a block cipher algorithm implementation for SERPENT, if you like it, let me know and i will share the C version which was the original one, or i can share other cryptographic libraries i have developed, yes, im a cryptographer and a mathematician, enjoy:

C++:
#ifndef SERPENT_CIPHER_CXX_H
#define SERPENT_CIPHER_CXX_H 1

#pragma once

#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <random>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

// ========== Attribute Macros ==========
#if defined(__GNUC__) || defined(__clang__)
#define __attr_nodiscard __attribute__((warn_unused_result))
#define __attr_malloc __attribute__((malloc))
#define __attr_hot __attribute__((hot))
#define __attr_cold __attribute__((cold))
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define __attr_nodiscard
#define __attr_malloc
#define __attr_hot
#define __attr_cold
#define likely(x) (x)
#define unlikely(x) (x)
#endif

#ifdef __cplusplus
#define __restrict__ __restrict
#define __noexcept noexcept
#define __const_noexcept noexcept
#else
#define __restrict__ restrict
#define __noexcept
#define __const_noexcept
#endif

/**
 * @brief Enum for supported key sizes (in bytes).
 */
enum class KEY_SIZE : size_t
{
    BITS_128 = 16,
    BITS_192 = 24,
    BITS_256 = 32
};

/** @brief Block cipher modes. */
struct ECB_Mode
{
};
struct CBC_Mode
{
};
struct CFB_Mode
{
};
struct OFB_Mode
{
};
struct CTR_Mode
{
};

/// @brief Internal error handling for the Serpent cipher.
namespace serpent_detail
{
/**
 * @brief Throws a runtime error with the provided message.
 * @param msg The error message.
 */
[[noreturn]] __attr_cold inline void fail(const char *msg)
{
    throw std::runtime_error(msg);
}
} // namespace serpent_detail

/// @brief Utility namespace for base64, hex, and binary encoding/decoding.
namespace serpent_util
{
static const char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char b64_pad = '=';

inline std::string toHex(const std::string &data)
{
    static const char hex[] = "0123456789abcdef";
    std::string out;
    out.reserve(data.size() * 2);
    for (uint8_t b : data)
    {
        out.push_back(hex[b >> 4]);
        out.push_back(hex[b & 0xF]);
    }
    return out;
}

inline std::string fromHex(const std::string &hexStr)
{
    std::string out;
    if (hexStr.size() % 2 != 0)
        serpent_detail::fail("Odd length hex string");
    out.reserve(hexStr.size() / 2);
    for (size_t i = 0; i < hexStr.size(); i += 2)
    {
        uint8_t hi = static_cast<uint8_t>(std::stoi(hexStr.substr(i, 1), nullptr, 16));
        uint8_t lo = static_cast<uint8_t>(std::stoi(hexStr.substr(i + 1, 1), nullptr, 16));
        out.push_back((hi << 4) | lo);
    }
    return out;
}

inline std::string toBinary(const std::string &data)
{
    std::string out;
    out.reserve(data.size() * 8);
    for (uint8_t b : data)
    {
        for (int i = 7; i >= 0; --i)
            out.push_back((b & (1 << i)) ? '1' : '0');
    }
    return out;
}

inline std::string fromBinary(const std::string &bin)
{
    if (bin.size() % 8 != 0)
        serpent_detail::fail("Binary string size must be multiple of 8");
    std::string out;
    for (size_t i = 0; i < bin.size(); i += 8)
    {
        uint8_t val = 0;
        for (int j = 0; j < 8; ++j)
        {
            val = (val << 1) | (bin[i + j] == '1' ? 1 : 0);
        }
        out.push_back(val);
    }
    return out;
}

inline std::string toBase64(const std::string &data)
{
    std::string out;
    int val = 0, valb = -6;
    for (uint8_t c : data)
    {
        val = (val << 8) + c;
        valb += 8;
        while (valb >= 0)
        {
            out.push_back(b64_table[(val >> valb) & 0x3F]);
            valb -= 6;
        }
    }
    if (valb > -6)
        out.push_back(b64_table[((val << 8) >> (valb + 8)) & 0x3F]);
    while (out.size() % 4)
        out.push_back(b64_pad);
    return out;
}

inline std::string fromBase64(const std::string &b64)
{
    int val = 0, valb = -8;
    std::string out;
    for (uint8_t c : b64)
    {
        if (c == b64_pad)
            break;
        const char *p = std::find(b64_table, b64_table + 64, c);
        if (p == b64_table + 64)
            break;
        val = (val << 6) + (p - b64_table);
        valb += 6;
        if (valb >= 0)
        {
            out.push_back(char((val >> valb) & 0xFF));
            valb -= 8;
        }
    }
    return out;
}
} // namespace serpent_util

/**
 * @class KeyIVGenerator
 * @brief Utility class for securely generating random keys and IVs.
 */
class KeyIVGenerator
{
  public:
    static std::string generateKey(KEY_SIZE keySize)
    {
        size_t size = static_cast<size_t>(keySize);
        std::string key(size, '\0');
        randomFill(reinterpret_cast<uint8_t *>(&key[0]), size);
        return key;
    }
    static std::string generateIV(size_t ivSize = 16)
    {
        std::string iv(ivSize, '\0');
        randomFill(reinterpret_cast<uint8_t *>(&iv[0]), ivSize);
        return iv;
    }
    static std::string toHex(const std::string &data)
    {
        return serpent_util::toHex(data);
    }

  private:
    static void randomFill(uint8_t *buf, size_t n)
    {
        std::random_device rd;
        for (size_t i = 0; i < n; ++i)
        {
            buf[i] = static_cast<uint8_t>(rd());
        }
    }
};

/**
 * @class SerpentResult
 * @brief Wrapper for encrypted/decrypted results supporting method chaining and conversion utilities.
 */
class SerpentResult
{
    std::string data_;

  public:
    SerpentResult(const std::string &data) : data_(data)
    {
    }
    SerpentResult toHex() const
    {
        return SerpentResult(serpent_util::toHex(data_));
    }
    SerpentResult fromHex() const
    {
        return SerpentResult(serpent_util::fromHex(data_));
    }
    SerpentResult toBase64() const
    {
        return SerpentResult(serpent_util::toBase64(data_));
    }
    SerpentResult fromBase64() const
    {
        return SerpentResult(serpent_util::fromBase64(data_));
    }
    SerpentResult toBinary() const
    {
        return SerpentResult(serpent_util::toBinary(data_));
    }
    SerpentResult fromBinary() const
    {
        return SerpentResult(serpent_util::fromBinary(data_));
    }
    SerpentResult toString() const
    {
        return *this;
    }
    SerpentResult toVector() const
    {
        return *this;
    }
    std::string asString() const
    {
        return data_;
    }
    std::vector<uint8_t> asVector() const
    {
        return std::vector<uint8_t>(data_.begin(), data_.end());
    }
    operator std::string() const
    {
        return data_;
    }
    operator std::vector<uint8_t>() const
    {
        return asVector();
    }
};

/**
 * @class Serpent
 * @brief Flexible, template-based implementation of the Serpent block cipher.
 * @tparam KEY_SZ The key size (default 256 bits).
 */
template <KEY_SIZE KEY_SZ = KEY_SIZE::BITS_256> class Serpent
{
  public:
    using uint = uint32_t;
    using uchar = uint8_t;
    static constexpr size_t BlockSize = 16;
    static constexpr size_t KeySize = static_cast<size_t>(KEY_SZ);
    static constexpr size_t Rounds = 32;
    using Block = std::array<uint, 4>;
    using SubKeys = std::array<Block, Rounds + 1>;

    // =================== STATIC ACCESS STRUCTS FOR ALL MODES =======================
    struct ECB
    {
        static SerpentResult Encrypt(const std::string &plaintext, const std::string &key)
        {
            Serpent cipher;
            return SerpentResult(cipher.encryptECB(plaintext, key));
        }
        static SerpentResult Decrypt(const std::string &ciphertext, const std::string &key)
        {
            Serpent cipher;
            return SerpentResult(cipher.decryptECB(ciphertext, key));
        }
    };
    struct CBC
    {
        static SerpentResult Encrypt(const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.encryptCBC(plaintext, key, iv));
        }
        static SerpentResult Decrypt(const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.decryptCBC(ciphertext, key, iv));
        }
    };
    struct CFB
    {
        static SerpentResult Encrypt(const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.encryptCFB(plaintext, key, iv));
        }
        static SerpentResult Decrypt(const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.decryptCFB(ciphertext, key, iv));
        }
    };
    struct OFB
    {
        static SerpentResult Encrypt(const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.encryptOFB(plaintext, key, iv));
        }
        static SerpentResult Decrypt(const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            Serpent cipher;
            return SerpentResult(cipher.decryptOFB(ciphertext, key, iv));
        }
    };
    struct CTR
    {
        static SerpentResult Encrypt(const std::string &plaintext, const std::string &key, const std::string &nonce)
        {
            Serpent cipher;
            return SerpentResult(cipher.encryptCTR(plaintext, key, nonce));
        }
        static SerpentResult Decrypt(const std::string &ciphertext, const std::string &key, const std::string &nonce)
        {
            Serpent cipher;
            return SerpentResult(cipher.decryptCTR(ciphertext, key, nonce));
        }
    };

    // ========== (Retain all original public/member functions for compatibility) ====

    template <typename... Args>
    __attr_nodiscard __attr_hot SerpentResult encrypt(const std::string &plaintext, const std::string &key, Args &&...args) const __const_noexcept
    {
        return SerpentResult(Policy::encrypt(*this, plaintext, key, std::forward<Args>(args)...));
    }
    template <typename... Args>
    __attr_nodiscard __attr_hot SerpentResult decrypt(const std::string &ciphertext, const std::string &key, Args &&...args) const __const_noexcept
    {
        return SerpentResult(Policy::decrypt(*this, ciphertext, key, std::forward<Args>(args)...));
    }

  private:
    std::string encryptBlock(const std::string &plaintext, const std::string &key) const __const_noexcept
    {
        if (unlikely(plaintext.size() != BlockSize))
            serpent_detail::fail("Serpent: encryptBlock: Plaintext must be 16 bytes.");
        if (unlikely(key.size() != KeySize))
            serpent_detail::fail("Serpent: encryptBlock: Key must match enum size.");
        std::string output(BlockSize, '\0');
        encryptBitslice(reinterpret_cast<const uchar *>(plaintext.data()), reinterpret_cast<const uchar *>(key.data()), reinterpret_cast<uchar *>(&output[0]));
        return output;
    }
    std::string decryptBlock(const std::string &ciphertext, const std::string &key) const __const_noexcept
    {
        if (unlikely(ciphertext.size() != BlockSize))
            serpent_detail::fail("Serpent: decryptBlock: Ciphertext must be 16 bytes.");
        if (unlikely(key.size() != KeySize))
            serpent_detail::fail("Serpent: decryptBlock: Key must match enum size.");
        std::string output(BlockSize, '\0');
        decryptBitslice(reinterpret_cast<const uchar *>(ciphertext.data()), reinterpret_cast<const uchar *>(key.data()), reinterpret_cast<uchar *>(&output[0]));
        return output;
    }
    std::string encryptECB(const std::string &plaintext, const std::string &key) const __const_noexcept
    {
        std::string padded = pkcs7Pad(plaintext);
        std::string ciphertext;
        ciphertext.reserve(padded.size());
        for (size_t i = 0; i < padded.size(); i += BlockSize)
            ciphertext += encryptBlock(padded.substr(i, BlockSize), key);
        return ciphertext;
    }
    std::string decryptECB(const std::string &ciphertext, const std::string &key) const __const_noexcept
    {
        if (unlikely(ciphertext.empty() || (ciphertext.size() % BlockSize) != 0))
            serpent_detail::fail("Serpent: decryptECB: Ciphertext size must be a positive multiple of 16 bytes.");
        std::string padded;
        padded.reserve(ciphertext.size());
        for (size_t i = 0; i < ciphertext.size(); i += BlockSize)
            padded += decryptBlock(ciphertext.substr(i, BlockSize), key);
        return pkcs7Unpad(padded);
    }
    std::string encryptCBC(const std::string &plaintext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        if (unlikely(iv.size() != BlockSize))
            serpent_detail::fail("Serpent: encryptCBC: IV must be 16 bytes.");
        std::string padded = pkcs7Pad(plaintext);
        std::string ciphertext;
        ciphertext.reserve(padded.size());
        std::string prev = iv;
        for (size_t i = 0; i < padded.size(); i += BlockSize)
        {
            std::string block = padded.substr(i, BlockSize);
            std::string xored = xorStrings(block, prev);
            std::string enc = encryptBlock(xored, key);
            ciphertext += enc;
            prev = enc;
        }
        return ciphertext;
    }
    std::string decryptCBC(const std::string &ciphertext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        if (unlikely(iv.size() != BlockSize))
            serpent_detail::fail("Serpent: decryptCBC: IV must be 16 bytes.");
        if (unlikely(ciphertext.empty() || (ciphertext.size() % BlockSize) != 0))
            serpent_detail::fail("Serpent: decryptCBC: Ciphertext size must be a positive multiple of 16 bytes.");
        std::string padded;
        padded.reserve(ciphertext.size());
        std::string prev = iv;
        for (size_t i = 0; i < ciphertext.size(); i += BlockSize)
        {
            std::string block = ciphertext.substr(i, BlockSize);
            std::string dec = decryptBlock(block, key);
            padded += xorStrings(dec, prev);
            prev = block;
        }
        return pkcs7Unpad(padded);
    }
    std::string encryptCFB(const std::string &plaintext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        if (unlikely(iv.size() != BlockSize))
            serpent_detail::fail("Serpent: encryptCFB: IV must be 16 bytes.");
        std::string ciphertext;
        ciphertext.reserve(((plaintext.size() + BlockSize - 1) / BlockSize) * BlockSize);
        std::string prev = iv;
        for (size_t i = 0; i < plaintext.size(); i += BlockSize)
        {
            std::string block = plaintext.substr(i, BlockSize);
            std::string enc = encryptBlock(prev, key);
            std::string out(BlockSize, 0);
            for (size_t j = 0; j < BlockSize; ++j)
                out[j] = (j < block.size()) ? (block[j] ^ enc[j]) : enc[j];
            ciphertext += out.substr(0, block.size());
            prev = out;
        }
        return ciphertext;
    }
    std::string decryptCFB(const std::string &ciphertext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        if (unlikely(iv.size() != BlockSize))
            serpent_detail::fail("Serpent: decryptCFB: IV must be 16 bytes.");
        std::string plaintext;
        plaintext.reserve(ciphertext.size());
        std::string prev = iv;
        for (size_t i = 0; i < ciphertext.size(); i += BlockSize)
        {
            std::string block = ciphertext.substr(i, BlockSize);
            std::string enc = encryptBlock(prev, key);
            std::string out(BlockSize, 0);
            for (size_t j = 0; j < block.size(); ++j)
                out[j] = block[j] ^ enc[j];
            plaintext += out.substr(0, block.size());
            prev = block + std::string(BlockSize - block.size(), '\0');
        }
        return plaintext;
    }
    std::string encryptOFB(const std::string &plaintext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        if (unlikely(iv.size() != BlockSize))
            serpent_detail::fail("Serpent: encryptOFB: IV must be 16 bytes.");
        std::string ciphertext;
        ciphertext.reserve(plaintext.size());
        std::string ofb = iv;
        for (size_t i = 0; i < plaintext.size(); i += BlockSize)
        {
            ofb = encryptBlock(ofb, key);
            std::string block = plaintext.substr(i, BlockSize);
            std::string out(BlockSize, 0);
            for (size_t j = 0; j < block.size(); ++j)
                out[j] = block[j] ^ ofb[j];
            ciphertext += out.substr(0, block.size());
        }
        return ciphertext;
    }
    std::string decryptOFB(const std::string &ciphertext, const std::string &key, const std::string &iv) const __const_noexcept
    {
        return encryptOFB(ciphertext, key, iv);
    }
    std::string encryptCTR(const std::string &plaintext, const std::string &key, const std::string &nonce) const __const_noexcept
    {
        if (unlikely(nonce.size() != BlockSize))
            serpent_detail::fail("Serpent: encryptCTR: Nonce must be 16 bytes.");
        std::string ciphertext;
        ciphertext.reserve(plaintext.size());
        std::string counter = nonce;
        for (size_t i = 0; i < plaintext.size(); i += BlockSize)
        {
            std::string keystream = encryptBlock(counter, key);
            std::string block = plaintext.substr(i, BlockSize);
            std::string out(BlockSize, 0);
            for (size_t j = 0; j < block.size(); ++j)
                out[j] = block[j] ^ keystream[j];
            ciphertext += out.substr(0, block.size());
            incrementCounter(counter);
        }
        return ciphertext;
    }
    std::string decryptCTR(const std::string &ciphertext, const std::string &key, const std::string &nonce) const __const_noexcept
    {
        return encryptCTR(ciphertext, key, nonce);
    }

    std::string pkcs7Pad(const std::string &data) const __noexcept
    {
        size_t padLen = BlockSize - (data.size() % BlockSize);
        if (padLen == 0)
            padLen = BlockSize;
        std::string padded = data;
        padded.append(padLen, static_cast<char>(padLen));
        return padded;
    }
    std::string pkcs7Unpad(const std::string &data) const
    {
        if (unlikely(data.empty() || data.size() % BlockSize != 0))
            serpent_detail::fail("Serpent: pkcs7Unpad: Invalid padding size.");
        uchar padLen = static_cast<uchar>(data.back());
        if (unlikely(padLen == 0 || padLen > BlockSize))
            serpent_detail::fail("Serpent: pkcs7Unpad: Invalid padding value.");
        for (size_t i = data.size() - padLen; i < data.size(); ++i)
        {
            if (unlikely(static_cast<uchar>(data[i]) != padLen))
                serpent_detail::fail("Serpent: pkcs7Unpad: Invalid padding content.");
        }
        return data.substr(0, data.size() - padLen);
    }
    static std::string xorStrings(const std::string &a, const std::string &b) __noexcept
    {
        if (unlikely(a.size() != b.size()))
            serpent_detail::fail("Serpent: xorStrings: Inputs must have equal size.");
        std::string out(a.size(), '\0');
        for (size_t i = 0; i < a.size(); ++i)
            out[i] = a[i] ^ b[i];
        return out;
    }
    static void incrementCounter(std::string &counter) __noexcept
    {
        for (int i = BlockSize - 1; i >= 0; --i)
        {
            uint8_t &b = reinterpret_cast<uint8_t &>(counter[i]);
            if (++b != 0)
                break;
        }
    }

    void encryptBitslice(const uchar *plaintext, const uchar *key, uchar *output) const __noexcept
    {
        SubKeys subkeys{};
        generateKeySchedule(subkeys, key);

        Block state = {};
        std::memcpy(state.data(), plaintext, BlockSize);

        for (size_t round = 0; round < Rounds; ++round)
        {
            xorBlock(state, subkeys[round]);
            applySBox(state, round % 8);
            if (round < Rounds - 1)
                linearTransform(state);
            else
                xorBlock(state, subkeys[Rounds]);
        }
        std::memcpy(output, state.data(), BlockSize);
    }
    void decryptBitslice(const uchar *ciphertext, const uchar *key, uchar *output) const __noexcept
    {
        SubKeys subkeys{};
        generateKeySchedule(subkeys, key);

        Block state = {};
        std::memcpy(state.data(), ciphertext, BlockSize);

        for (int round = Rounds - 1; round >= 0; --round)
        {
            if (round < static_cast<int>(Rounds) - 1)
                inverseLinearTransform(state);
            else
                xorBlock(state, subkeys[Rounds]);
            inverseSBox(state, round % 8);
            xorBlock(state, subkeys[round]);
        }
        std::memcpy(output, state.data(), BlockSize);
    }

    static constexpr uint phi = 0x9e3779b9;

    void applySBox(Block &state, int sboxIdx) const __noexcept
    {
        Block newState = {};
        for (int bit = 0; bit < 32; ++bit)
        {
            uint input = ((state[0] >> bit) & 1) << 0 | ((state[1] >> bit) & 1) << 1 | ((state[2] >> bit) & 1) << 2 | ((state[3] >> bit) & 1) << 3;
            uint output = SBox[sboxIdx][input];
            for (int w = 0; w < 4; ++w)
                newState[w] |= ((output >> w) & 1) << bit;
        }
        state = newState;
    }
    void inverseSBox(Block &state, int sboxIdx) const __noexcept
    {
        Block newState = {};
        for (int bit = 0; bit < 32; ++bit)
        {
            uint input = ((state[0] >> bit) & 1) << 0 | ((state[1] >> bit) & 1) << 1 | ((state[2] >> bit) & 1) << 2 | ((state[3] >> bit) & 1) << 3;
            uint output = SBoxInverse[sboxIdx][input];
            for (int w = 0; w < 4; ++w)
                newState[w] |= ((output >> w) & 1) << bit;
        }
        state = newState;
    }
    void linearTransform(Block &state) const __noexcept
    {
        state[1] = rotl(state[1] ^ rotl(state[0], 13) ^ rotl(state[2], 3), 1);
        state[3] = rotl(state[3] ^ rotl(state[2], 3) ^ (rotl(state[0], 13) << 3), 7);
        state[0] = rotl(rotl(state[0], 13) ^ state[1] ^ state[3], 5);
        state[2] = rotl(rotl(state[2], 3) ^ state[3] ^ (state[1] << 7), 22);
    }
    void inverseLinearTransform(Block &state) const __noexcept
    {
        state[2] = rotl(state[2], 10) ^ state[3] ^ (state[1] << 7);
        state[0] = rotl(state[0], 27) ^ state[1] ^ state[3];
        state[3] = rotl(state[3], 25);
        state[1] = rotl(state[1], 31);
        state[3] = state[3] ^ state[2] ^ (state[0] << 3);
        state[1] = state[1] ^ state[0] ^ state[2];
        state[2] = rotl(state[2], 29);
        state[0] = rotl(state[0], 19);
    }

    void generateKeySchedule(SubKeys &subkeys, const uchar *key) const __noexcept
    {
        std::array<uint, 8> keySplit{};
        std::array<uint, 140> interKey{};
        prepareKey(keySplit, key);
        expandKey(interKey, keySplit);
        generateSubkeys(subkeys, interKey);
    }
    void prepareKey(std::array<uint, 8> &keySplit, const uchar *key) const __noexcept
    {
        std::array<uchar, 32> paddedKey = {};
        std::memset(paddedKey.data(), 0, 32);
        std::memcpy(paddedKey.data(), key, KeySize);
        if (KeySize < 32)
        {
            paddedKey[KeySize] = 0x01;
        }
        for (int i = 0; i < 8; ++i)
            keySplit[i] = *reinterpret_cast<const uint *>(&paddedKey[i * 4]);
    }
    void expandKey(std::array<uint, 140> &interKey, const std::array<uint, 8> &keySplit) const __noexcept
    {
        std::copy(keySplit.begin(), keySplit.end(), interKey.begin());
        for (int i = 8; i < 140; ++i)
            interKey[i] = rotl((interKey[i - 8] ^ interKey[i - 5] ^ interKey[i - 3] ^ interKey[i - 1] ^ phi ^ (i - 8)), 11);
    }
    void generateSubkeys(SubKeys &subkeys, const std::array<uint, 140> &interKey) const __noexcept
    {
        for (int i = 0; i <= static_cast<int>(Rounds); ++i)
        {
            int box = (Rounds + 3 - i) % 32;
            for (int j = 0; j < 32; ++j)
            {
                uint sboxOut = SBox[box % 8][((interKey[8 + 0 + (4 * i)] >> j) & 1) << 0 | ((interKey[8 + 1 + (4 * i)] >> j) & 1) << 1 |
                                             ((interKey[8 + 2 + (4 * i)] >> j) & 1) << 2 | ((interKey[8 + 3 + (4 * i)] >> j) & 1) << 3];
                for (int l = 0; l < 4; ++l)
                    subkeys[i][l] |= ((sboxOut >> l) & 1) << j;
            }
        }
    }
    static constexpr uint rotl(uint x, int p) __noexcept
    {
        return ((x << p) | (x >> (32 - p))) & 0xffffffffu;
    }
    static void xorBlock(Block &a, const Block &b) __noexcept
    {
        for (int i = 0; i < 4; ++i)
            a[i] ^= b[i];
    }
    static constexpr uint SBox[8][16] = {{3, 8, 15, 1, 10, 6, 5, 11, 14, 13, 4, 2, 7, 0, 9, 12}, {15, 12, 2, 7, 9, 0, 5, 10, 1, 11, 14, 8, 6, 13, 3, 4},
                                         {8, 6, 7, 9, 3, 12, 10, 15, 13, 1, 14, 4, 0, 11, 5, 2}, {0, 15, 11, 8, 12, 9, 6, 3, 13, 1, 2, 4, 10, 7, 5, 14},
                                         {1, 15, 8, 3, 12, 0, 11, 6, 2, 5, 4, 10, 9, 14, 7, 13}, {15, 5, 2, 11, 4, 10, 9, 12, 0, 3, 14, 8, 13, 6, 7, 1},
                                         {7, 2, 12, 5, 8, 4, 6, 11, 14, 9, 1, 15, 13, 3, 10, 0}, {1, 13, 15, 0, 14, 8, 2, 11, 7, 4, 12, 10, 9, 3, 5, 6}};
    static constexpr uint SBoxInverse[8][16] = {{13, 3, 11, 0, 10, 6, 5, 12, 1, 14, 4, 7, 15, 9, 8, 2}, {5, 8, 2, 14, 15, 6, 12, 3, 11, 4, 7, 9, 1, 13, 10, 0},
                                                {12, 9, 15, 4, 11, 14, 1, 2, 0, 3, 6, 13, 5, 8, 10, 7}, {0, 9, 10, 7, 11, 14, 6, 13, 3, 5, 12, 2, 4, 8, 15, 1},
                                                {5, 0, 8, 3, 10, 9, 7, 14, 2, 12, 11, 6, 4, 15, 13, 1}, {8, 15, 2, 9, 4, 1, 13, 14, 11, 6, 5, 3, 7, 12, 10, 0},
                                                {15, 10, 1, 13, 5, 3, 6, 0, 4, 9, 14, 7, 2, 12, 8, 11}, {3, 0, 6, 13, 9, 14, 15, 8, 5, 12, 11, 7, 10, 1, 4, 2}};

    // --- Mode Policies (for backwards compatibility with member encrypt()/decrypt()) ---
    template <typename C> struct ECB_Policy
    {
        static std::string encrypt(const C &cipher, const std::string &plaintext, const std::string &key)
        {
            return cipher.encryptECB(plaintext, key);
        }
        static std::string decrypt(const C &cipher, const std::string &ciphertext, const std::string &key)
        {
            return cipher.decryptECB(ciphertext, key);
        }
    };
    template <typename C> struct CBC_Policy
    {
        static std::string encrypt(const C &cipher, const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            return cipher.encryptCBC(plaintext, key, iv);
        }
        static std::string decrypt(const C &cipher, const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            return cipher.decryptCBC(ciphertext, key, iv);
        }
    };
    template <typename C> struct CFB_Policy
    {
        static std::string encrypt(const C &cipher, const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            return cipher.encryptCFB(plaintext, key, iv);
        }
        static std::string decrypt(const C &cipher, const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            return cipher.decryptCFB(ciphertext, key, iv);
        }
    };
    template <typename C> struct OFB_Policy
    {
        static std::string encrypt(const C &cipher, const std::string &plaintext, const std::string &key, const std::string &iv)
        {
            return cipher.encryptOFB(plaintext, key, iv);
        }
        static std::string decrypt(const C &cipher, const std::string &ciphertext, const std::string &key, const std::string &iv)
        {
            return cipher.decryptOFB(ciphertext, key, iv);
        }
    };
    template <typename C> struct CTR_Policy
    {
        static std::string encrypt(const C &cipher, const std::string &plaintext, const std::string &key, const std::string &nonce)
        {
            return cipher.encryptCTR(plaintext, key, nonce);
        }
        static std::string decrypt(const C &cipher, const std::string &ciphertext, const std::string &key, const std::string &nonce)
        {
            return cipher.decryptCTR(ciphertext, key, nonce);
        }
    };

    using Policy = ECB_Policy<Serpent>; // Default to ECB in member .encrypt/.decrypt
};

#endif
 
and here is how you can use it:

C++:
#include "serpent.hpp"
#include <iostream>

int main() {
    using serpent256 = Serpent<KEY_SIZE::BITS_256>;
    std::string message = "this is a test for my serpent cipher code!";

    // Generate a random key and IV/nonce for demonstration
    std::string key = KeyIVGenerator::generateKey(KEY_SIZE::BITS_256);
    std::string iv  = KeyIVGenerator::generateIV();
    std::string nonce = KeyIVGenerator::generateIV(); // For CTR

    
    // --- CTR Mode ---
    auto ctr_ct = serpent256::CTR::Encrypt(message, key, nonce);
    auto ctr_pt = serpent256::CTR::Decrypt(ctr_ct.asString(), key, nonce);
    std::cout << "[CTR] Encrypted (hex): " << ctr_ct.toHex().asString() << "\n";
    std::cout << "[CTR] Decrypted: " << ctr_pt.asString() << "\n\n";

    return 0;
}
 
and here is how you can use it:

C++:
#include "serpent.hpp"
#include <iostream>

int main() {
    using serpent256 = Serpent<KEY_SIZE::BITS_256>;
    std::string message = "this is a test for my serpent cipher code!";

    // Generate a random key and IV/nonce for demonstration
    std::string key = KeyIVGenerator::generateKey(KEY_SIZE::BITS_256);
    std::string iv  = KeyIVGenerator::generateIV();
    std::string nonce = KeyIVGenerator::generateIV(); // For CTR

   
    // --- CTR Mode ---
    auto ctr_ct = serpent256::CTR::Encrypt(message, key, nonce);
    auto ctr_pt = serpent256::CTR::Decrypt(ctr_ct.asString(), key, nonce);
    std::cout << "[CTR] Encrypted (hex): " << ctr_ct.toHex().asString() << "\n";
    std::cout << "[CTR] Decrypted: " << ctr_pt.asString() << "\n\n";

    return 0;
}
Hi there,
What was the inspiration for this?
 

Buy us a coffee!

Buy me a coffee.
Back
Top Bottom