Initial import of libdpf.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 14:08:32 -06:00
commit e4e666f459
4563 changed files with 1690372 additions and 0 deletions

21
thirdparty/lowmc/LICENSE.md vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 tyti
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

406
thirdparty/lowmc/LowMC.cpp vendored Normal file
View file

@ -0,0 +1,406 @@
// Vendored from https://github.com/LowMC/lowmc
// commit e847fb160ad8ca1f373efd91a55b6d67f7deb425
// Local changes: namespace lowmc; definitions are inline so a header-only
// user can include this file; Grain state restarts in instantiate_LowMC.
#include <vector>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include "LowMC.h"
#include <bitset>
namespace lowmc {
// Shared by every LowMC instance. instantiate_LowMC restarts it.
inline std::bitset<80> & grain_state() {
static std::bitset<80> state;
return state;
}
/////////////////////////////
// LowMC functions //
/////////////////////////////
inline block LowMC::encrypt (const block message) {
block c = message ^ roundkeys[0];
for (unsigned r = 1; r <= rounds; ++r) {
c = Substitution(c);
c = MultiplyWithGF2Matrix(LinMatrices[r-1], c);
c ^= roundconstants[r-1];
c ^= roundkeys[r];
}
return c;
}
inline block LowMC::decrypt (const block message) {
block c = message;
for (unsigned r = rounds; r > 0; --r) {
c ^= roundkeys[r];
c ^= roundconstants[r-1];
c = MultiplyWithGF2Matrix(invLinMatrices[r-1], c);
c = invSubstitution(c);
}
c ^= roundkeys[0];
return c;
}
inline void LowMC::set_key (keyblock k) {
key = k;
keyschedule();
}
inline void LowMC::print_matrices() {
std::cout << "LowMC matrices and constants" << std::endl;
std::cout << "============================" << std::endl;
std::cout << "Block size: " << blocksize << std::endl;
std::cout << "Key size: " << keysize << std::endl;
std::cout << "Rounds: " << rounds << std::endl;
std::cout << std::endl;
std::cout << "Linear layer matrices" << std::endl;
std::cout << "---------------------" << std::endl;
for (unsigned r = 1; r <= rounds; ++r) {
std::cout << "Linear layer " << r << ":" << std::endl;
for (auto row: LinMatrices[r-1]) {
std::cout << "[";
for (unsigned i = 0; i < blocksize; ++i) {
std::cout << row[i];
if (i != blocksize - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
}
std::cout << std::endl;
}
std::cout << "Round constants" << std::endl;
std::cout << "---------------------" << std::endl;
for (unsigned r = 1; r <= rounds; ++r) {
std::cout << "Round constant " << r << ":" << std::endl;
std::cout << "[";
for (unsigned i = 0; i < blocksize; ++i) {
std::cout << roundconstants[r-1][i];
if (i != blocksize - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
std::cout << std::endl;
}
std::cout << "Round key matrices" << std::endl;
std::cout << "---------------------" << std::endl;
for (unsigned r = 0; r <= rounds; ++r) {
std::cout << "Round key matrix " << r << ":" << std::endl;
for (auto row: KeyMatrices[r]) {
std::cout << "[";
for (unsigned i = 0; i < keysize; ++i) {
std::cout << row[i];
if (i != keysize - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
}
if (r != rounds) {
std::cout << std::endl;
}
}
}
/////////////////////////////
// LowMC private functions //
/////////////////////////////
inline block LowMC::Substitution (const block message) {
block temp = 0;
//Get the identity part of the message
temp ^= (message >> 3*numofboxes);
//Get the rest through the Sboxes
for (unsigned i = 1; i <= numofboxes; ++i) {
temp <<= 3;
temp ^= Sbox[ ((message >> 3*(numofboxes-i))
& block(0x7)).to_ulong()];
}
return temp;
}
inline block LowMC::invSubstitution (const block message) {
block temp = 0;
//Get the identity part of the message
temp ^= (message >> 3*numofboxes);
//Get the rest through the invSboxes
for (unsigned i = 1; i <= numofboxes; ++i) {
temp <<= 3;
temp ^= invSbox[ ((message >> 3*(numofboxes-i))
& block(0x7)).to_ulong()];
}
return temp;
}
inline block LowMC::MultiplyWithGF2Matrix
(const std::vector<block> matrix, const block message) {
block temp = 0;
for (unsigned i = 0; i < blocksize; ++i) {
temp[i] = (message & matrix[i]).count() % 2;
}
return temp;
}
inline block LowMC::MultiplyWithGF2Matrix_Key
(const std::vector<keyblock> matrix, const keyblock k) {
block temp = 0;
for (unsigned i = 0; i < blocksize; ++i) {
temp[i] = (k & matrix[i]).count() % 2;
}
return temp;
}
inline void LowMC::keyschedule () {
roundkeys.clear();
for (unsigned r = 0; r <= rounds; ++r) {
roundkeys.push_back( MultiplyWithGF2Matrix_Key (KeyMatrices[r], key) );
}
return;
}
inline void LowMC::instantiate_LowMC () {
// Grain is specified to start from the all-ones state. Restart so a
// later instance does not continue the previous instance's stream.
grain_state().reset();
// Create LinMatrices and invLinMatrices
LinMatrices.clear();
invLinMatrices.clear();
for (unsigned r = 0; r < rounds; ++r) {
// Create matrix
std::vector<block> mat;
// Fill matrix with random bits
do {
mat.clear();
for (unsigned i = 0; i < blocksize; ++i) {
mat.push_back( getrandblock () );
}
// Repeat if matrix is not invertible
} while ( rank_of_Matrix(mat) != blocksize );
LinMatrices.push_back(mat);
invLinMatrices.push_back(invert_Matrix (LinMatrices.back()));
}
// Create roundconstants
roundconstants.clear();
for (unsigned r = 0; r < rounds; ++r) {
roundconstants.push_back( getrandblock () );
}
// Create KeyMatrices
KeyMatrices.clear();
for (unsigned r = 0; r <= rounds; ++r) {
// Create matrix
std::vector<keyblock> mat;
// Fill matrix with random bits
do {
mat.clear();
for (unsigned i = 0; i < blocksize; ++i) {
mat.push_back( getrandkeyblock () );
}
// Repeat if matrix is not of maximal rank
} while ( rank_of_Matrix_Key(mat) < std::min(blocksize, keysize) );
KeyMatrices.push_back(mat);
}
return;
}
/////////////////////////////
// Binary matrix functions //
/////////////////////////////
inline unsigned LowMC::rank_of_Matrix (const std::vector<block> matrix) {
std::vector<block> mat; //Copy of the matrix
for (auto u : matrix) {
mat.push_back(u);
}
unsigned size = mat[0].size();
//Transform to upper triangular matrix
unsigned row = 0;
for (unsigned col = 1; col <= size; ++col) {
if ( !mat[row][size-col] ) {
unsigned r = row;
while (r < mat.size() && !mat[r][size-col]) {
++r;
}
if (r >= mat.size()) {
continue;
} else {
auto temp = mat[row];
mat[row] = mat[r];
mat[r] = temp;
}
}
for (unsigned i = row+1; i < mat.size(); ++i) {
if ( mat[i][size-col] ) mat[i] ^= mat[row];
}
++row;
if (row == size) break;
}
return row;
}
inline unsigned LowMC::rank_of_Matrix_Key (const std::vector<keyblock> matrix) {
std::vector<keyblock> mat; //Copy of the matrix
for (auto u : matrix) {
mat.push_back(u);
}
unsigned size = mat[0].size();
//Transform to upper triangular matrix
unsigned row = 0;
for (unsigned col = 1; col <= size; ++col) {
if ( !mat[row][size-col] ) {
unsigned r = row;
while (r < mat.size() && !mat[r][size-col]) {
++r;
}
if (r >= mat.size()) {
continue;
} else {
auto temp = mat[row];
mat[row] = mat[r];
mat[r] = temp;
}
}
for (unsigned i = row+1; i < mat.size(); ++i) {
if ( mat[i][size-col] ) mat[i] ^= mat[row];
}
++row;
if (row == size) break;
}
return row;
}
inline std::vector<block> LowMC::invert_Matrix (const std::vector<block> matrix) {
std::vector<block> mat; //Copy of the matrix
for (auto u : matrix) {
mat.push_back(u);
}
std::vector<block> invmat(blocksize, 0); //To hold the inverted matrix
for (unsigned i = 0; i < blocksize; ++i) {
invmat[i][i] = 1;
}
unsigned size = mat[0].size();
//Transform to upper triangular matrix
unsigned row = 0;
for (unsigned col = 0; col < size; ++col) {
if ( !mat[row][col] ) {
unsigned r = row+1;
while (r < mat.size() && !mat[r][col]) {
++r;
}
if (r >= mat.size()) {
continue;
} else {
auto temp = mat[row];
mat[row] = mat[r];
mat[r] = temp;
temp = invmat[row];
invmat[row] = invmat[r];
invmat[r] = temp;
}
}
for (unsigned i = row+1; i < mat.size(); ++i) {
if ( mat[i][col] ) {
mat[i] ^= mat[row];
invmat[i] ^= invmat[row];
}
}
++row;
}
//Transform to identity matrix
for (unsigned col = size; col > 0; --col) {
for (unsigned r = 0; r < col-1; ++r) {
if (mat[r][col-1]) {
mat[r] ^= mat[col-1];
invmat[r] ^= invmat[col-1];
}
}
}
return invmat;
}
///////////////////////
// Pseudorandom bits //
///////////////////////
inline block LowMC::getrandblock () {
block tmp = 0;
for (unsigned i = 0; i < blocksize; ++i) tmp[i] = getrandbit ();
return tmp;
}
inline keyblock LowMC::getrandkeyblock () {
keyblock tmp = 0;
for (unsigned i = 0; i < keysize; ++i) tmp[i] = getrandbit ();
return tmp;
}
// Uses the Grain LSFR as self-shrinking generator to create pseudorandom bits
// Is initialized with the all 1s state
// The first 160 bits are thrown away
inline bool LowMC::getrandbit () {
std::bitset<80> & state = grain_state(); // 80 bit LFSR state
bool tmp = 0;
//If state has not been initialized yet
if (state.none ()) {
state.set (); //Initialize with all bits set
//Throw the first 160 bits away
for (unsigned i = 0; i < 160; ++i) {
//Update the state
tmp = state[0] ^ state[13] ^ state[23]
^ state[38] ^ state[51] ^ state[62];
state >>= 1;
state[79] = tmp;
}
}
//choice records whether the first bit is 1 or 0.
//The second bit is produced if the first bit is 1.
bool choice = false;
do {
//Update the state
tmp = state[0] ^ state[13] ^ state[23]
^ state[38] ^ state[51] ^ state[62];
state >>= 1;
state[79] = tmp;
choice = tmp;
tmp = state[0] ^ state[13] ^ state[23]
^ state[38] ^ state[51] ^ state[62];
state >>= 1;
state[79] = tmp;
} while (! choice);
return tmp;
}
} // namespace lowmc

94
thirdparty/lowmc/LowMC.h vendored Normal file
View file

@ -0,0 +1,94 @@
#ifndef __LowMC_h__
#define __LowMC_h__
// Vendored from https://github.com/LowMC/lowmc
// commit e847fb160ad8ca1f373efd91a55b6d67f7deb425
// Local changes: namespace lowmc, and the parameters below.
// LowMCv3 instance for a 128-bit block and key with 10 S-boxes, at data
// complexity 2^128: `determine_rounds.py 128 10 128 128` reports 32 rounds.
#include <bitset>
#include <vector>
#include <string>
namespace lowmc {
const unsigned numofboxes = 10; // Number of Sboxes
const unsigned blocksize = 128; // Block size in bits
const unsigned keysize = 128; // Key size in bits
const unsigned rounds = 32; // Number of rounds
const unsigned identitysize = blocksize - 3*numofboxes;
// Size of the identity part in the Sbox layer
typedef std::bitset<blocksize> block; // Store messages and states
typedef std::bitset<keysize> keyblock;
class LowMC {
public:
LowMC (keyblock k = 0) {
key = k;
instantiate_LowMC();
keyschedule();
};
block encrypt (const block message);
block decrypt (const block message);
void set_key (keyblock k);
void print_matrices();
private:
// LowMC private data members //
// The Sbox and its inverse
const std::vector<unsigned> Sbox =
{0x00, 0x01, 0x03, 0x06, 0x07, 0x04, 0x05, 0x02};
const std::vector<unsigned> invSbox =
{0x00, 0x01, 0x07, 0x02, 0x05, 0x06, 0x03, 0x04};
std::vector<std::vector<block>> LinMatrices;
// Stores the binary matrices for each round
std::vector<std::vector<block>> invLinMatrices;
// Stores the inverses of LinMatrices
std::vector<block> roundconstants;
// Stores the round constants
keyblock key = 0;
//Stores the master key
std::vector<std::vector<keyblock>> KeyMatrices;
// Stores the matrices that generate the round keys
std::vector<block> roundkeys;
// Stores the round keys
// LowMC private functions //
block Substitution (const block message);
// The substitution layer
block invSubstitution (const block message);
// The inverse substitution layer
block MultiplyWithGF2Matrix
(const std::vector<block> matrix, const block message);
// For the linear layer
block MultiplyWithGF2Matrix_Key
(const std::vector<keyblock> matrix, const keyblock k);
// For generating the round keys
void keyschedule ();
//Creates the round keys from the master key
void instantiate_LowMC ();
//Fills the matrices and roundconstants with pseudorandom bits
// Binary matrix functions //
unsigned rank_of_Matrix (const std::vector<block> matrix);
unsigned rank_of_Matrix_Key (const std::vector<keyblock> matrix);
std::vector<block> invert_Matrix (const std::vector<block> matrix);
// Random bits functions //
block getrandblock ();
keyblock getrandkeyblock ();
bool getrandbit ();
};
} // namespace lowmc
#endif

23
thirdparty/lowmc/README.md vendored Normal file
View file

@ -0,0 +1,23 @@
# LowMC implementation
This is a C++ implementation of the LowMC block cipher family. The
parameters (block size, number of S-boxes in the substitution layer, number
of rounds, key size) are defined in `LowMC.h`. Compilation requires support
of C++11 features.
The files `LowMC.h` and `LowMC.cpp` contain the relevant code. `test.cpp`
contains a short example usage.
The file `determine_rounds.py` contains a Python script that determines
the number of rounds needed for LowMC to be secure in dependence on
the other parameters: the block size *n*, the number of S-boxes per layer *m*,
the log2 of the allowed data complexity *d*, and the key size *k*.
Example usage: `python3 determine_rounds.py 256 63 128 128`
## Script for generating the matrices and and constants
The python script `generate_matrices.py` can be used to generate the matrices
for the linear layer and the key schedule as well as the round constants.
They are written to a file named `matrices_and_constants.dat`. This is script
can provide the matrices for use in cryptanalysis. It is _not_ needed for the
reference implementation which creates the matrices and constants internally.