Merge pull request #1 from vacp2p/review

Update in accordance with the review results
This commit is contained in:
Aleksei Vambol
2025-02-12 23:39:03 +02:00
committed by GitHub
5 changed files with 87 additions and 16 deletions

45
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Install the stable Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt, clippy
- name: Run cargo fmt
run: cargo fmt -- --check
- name: Run cargo clippy
run: cargo clippy --release -- -D warnings
test:
name: test - ${{ matrix.platform }}
runs-on: ${{ matrix.platform }}
strategy:
matrix:
platform: [ ubuntu-latest, macos-latest ]
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Install the stable Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Run cargo test
run: cargo test --release

View File

@@ -2,6 +2,12 @@
name = "mdsecheck"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "Tools for generating unconditionally secure square MDS matrices over prime finite fields for partial substitution-permutation networks, which are widespread designs of symmetric ciphers and hash functions."
documentation = "https://github.com/vacp2p/mdsecheck"
homepage = "https://vac.dev"
keywords = ["mds-matrices", "p-spn", "spn", "hash-functions", "symmetric-ciphers", "cryptography"]
repository = "https://github.com/vacp2p/mdsecheck"
[dependencies]
ark-ff = { version = "0.5.0", default-features = false, features = ["asm"] }
@@ -11,4 +17,4 @@ rand = "0.8.5"
[dev-dependencies]
ark-bn254 = "0.5.0"
rand_chacha = "0.3.0"
rand_chacha = "0.3.0"

View File

@@ -1,14 +1,17 @@
# MDSECheck
The crate provides tools for generating random square [MDS matrices](https://en.wikipedia.org/wiki/MDS_matrix) over prime finite fields and applying the MDSECheck method to check such matrices for unconditional security as the components of affine permutation boxes of [partial substitution-permutation networks (P-SPNs)](https://eprint.iacr.org/2020/500.pdf), which are widespread designs of the modern symmetric ciphers and hash functions. The used data types of field elements and polynomials are provided by the crates [ark-ff](https://docs.rs/ark-ff) and [ark-poly](https://docs.rs/ark-poly). The auxiliary tools in the crate modules are accessible as well.
The round unconditional P-SPN security level of the square MDS matrix M is defined as l rounds, where l is a positive integer, if and only if M simultaneously satisfies the following conditions:
1. The [minimal polynomials](https://en.wikipedia.org/wiki/Minimal_polynomial_(linear_algebra)) of M, M<sup>2</sup>, ..., M<sup>l</sup> have maximum degree and are irreducible.
2. The minimal polynomial of M<sup>l + 1</sup> is not of maximum degree or not irreducible.
## Definition of unconditional P-SPN security of square MDS matrices
The round unconditional P-SPN security level of the square MDS matrix `M` is defined as `l` rounds, where `l` is a positive integer, if and only if `M` simultaneously satisfies the following conditions:
1. The [minimal polynomials](https://en.wikipedia.org/wiki/Minimal_polynomial_(linear_algebra)) of `M`, `M²`, ..., `Mˡ` have maximum degree and are irreducible.
2. The minimal polynomial of `Mˡ⁺¹` is not of maximum degree or not irreducible.
Theorem 8 in the paper ["Proving Resistance Against Infinitely Long Subspace Trails: How to Choose the Linear Layer"](https://eprint.iacr.org/2020/500.pdf) by L. Grassi, C. Rechberger and M. Schofnegger ensures that if the round unconditional P-SPN security level of the matrix is l, then "there is no infinitely long [subspace trail](https://eprint.iacr.org/2020/500.pdf) with/without active S-boxes of period less than or equal to l" regardless of the structure of the P-SPN affine permutation box using this matrix, but does not provide the same guarantees for larger periods. This independence from the P-SPN affine permutation boxes is the reason for using the term "unconditional security". Once an MDS matrix with the round unconditional P-SPN security level l has been chosen, it can protect any P-SPN with at most l rounds from the ["attacks based on infinitely long truncated differentials with probability 1"](https://eprint.iacr.org/2020/500.pdf).
Theorem 8 in the paper ["Proving Resistance Against Infinitely Long Subspace Trails: How to Choose the Linear Layer"](https://eprint.iacr.org/2020/500.pdf) by L. Grassi, C. Rechberger and M. Schofnegger ensures that if the round unconditional P-SPN security level of a square MDS matrix is `l`, then "there is no infinitely long [subspace trail](https://eprint.iacr.org/2020/500.pdf) with/without active S-boxes of period less than or equal to `l`" regardless of the structure of the P-SPN affine permutation box using this matrix, but does not provide the same guarantees for larger periods. This independence from the P-SPN affine permutation boxes is the reason for using the term "unconditional security". Once an MDS matrix with the round unconditional P-SPN security level `l` has been chosen, it can protect any P-SPN with at most `l` rounds from the ["attacks based on infinitely long truncated differentials with probability 1"](https://eprint.iacr.org/2020/500.pdf).
## Implemented approach to the security checks
To check whether the round unconditional P-SPN security level of the specified matrix is no less than the specified bound, the crate provides the implementation of the MDSECheck method, whose name is derived from the words "MDS", "security", "elaborated" and "check". An incomplete description of this novel method can be found in [this report](https://notes.status.im/CVMoa6EcTmS2D4VPBCsH2w), while a reference to a more detailed article dedicated to MDSECheck is planned to be included in the next version of the crate.
# Example
## Usage example
```rust
use ark_bn254::Fr;
use mdsecheck::{random_cauchy, security_level};
@@ -25,4 +28,7 @@ loop {
break;
}
}
```
```
## Disclaimer
The current version of this crate has not undergone a third-party security audit and is not intended for production use without proper security review.

View File

@@ -49,30 +49,41 @@ pub fn security_level<F: PrimeField>(a: &[impl AsRef<[F]>], l: u32) -> Option<u3
// be used in P-SPN, or the second argument is 0
return None;
}
// Using the Krylovs method fragment, which successfully
// Using the Krylov method fragment, which successfully
// computes the minimal polynomial of the matrix, provided
// that the polynomial is of maximum degree and irreducible,
// fails if the polynomial is not of maximum degree and may
// fail in other cases
let mut m = Vec::<Vec<F>>::with_capacity(n);
// In this case, any non-zero vector can be chosen as the first Krylov vector
m.push(vec![F::ONE; n]);
for i in 0..n - 1 {
// Computing all required subsequent Krylov vectors except the last one
m.push(mat::product_vector(a, &m[i])?);
}
// The last Krylov vector is stored separately because it is the one
// that will be represented as a linear combination of the previous
// Krylov vectors, provided that they are linearly independent
let b = mat::product_vector(a, &m[n - 1])?;
// Computing the horizontal concatenation of transposed elements of
// the computed Krylov vector sequence without its last element
for y in 0..n {
for x in 0..y {
(m[y][x], m[x][y]) = (m[x][y], m[y][x]);
}
}
// If the function returns at this point, then the Krylovs method fragment
// has failed. Consequently, the matrix is not unconditionally P-SPN secure
// Computing the coefficients of the aforementioned linear combination. If the
// function returns at this point, then the vectors of this linear combination
// are linearly dependent, implying that the minimal polynomial of the matrix
// cannot be of maximum degree and irreducible, which has allowed the Krylov
// method fragment to fail. Thus, the matrix is not unconditionally P-SPN secure
let mut s = mat::system_solution(&m, &b)?;
// Computing the minimal polynomial from the coefficients of the linear combination
s.iter_mut().for_each(|e| *e = -*e);
s.push(F::ONE);
let c = DensePolynomial::<F>::from_coefficients_vec(s);
// Checking the irreducibility of the minimal polynomial, which has been found using
// the Krylovs method fragment, by means of Algorithm 2.2.9 in the book "Prime Numbers -
// the Krylov method fragment, by means of Algorithm 2.2.9 in the book "Prime Numbers -
// A Computational Perspective (2nd edn.)" by R. Crandall and C. Pomerance. Some values
// computed in this step will be used in the next one
let f = num::prime_divisors(n as u32)

View File

@@ -7,7 +7,7 @@ pub fn prime_divisors(mut n: u32) -> Vec<u32> {
return vec![];
}
let mut p = Vec::with_capacity(n.ilog2() as usize);
if n & 1 == 0 {
if n % 2 == 0 {
p.push(2);
n >>= n.trailing_zeros();
}
@@ -30,10 +30,13 @@ pub fn prime_divisors(mut n: u32) -> Vec<u32> {
extract(d, &mut n, &mut p);
b = sqrt(n);
}
// A trial divisor is either 5 or 6k + 1 or 6k + 5 for
// some positive integer k. Therefore, the difference
// between the (j + 1)-th and the j-th trial divisor
// is 2, if j is odd, and 4 otherwise
// At this point, a trial divisor is either 5 or 6k + 1
// or 6k + 5 for some positive integer k. Therefore, the
// difference between the (j + 1)-th and the j-th trial
// divisor is 2, if j is odd, and 4 otherwise. The value
// of the difference for the next iteration is computed
// from the current difference value in accordance with
// the equalities "2 xor 6 = 4" and "4 xor 6 = 2"
(d, s) = (d + s, s ^ 6);
}
if n > 1 {