Everything except docs, comments and autotests

This commit is contained in:
AlekseiVambol
2025-01-29 18:48:06 +02:00
parent f74355d7b5
commit 4cbb210354
7 changed files with 712 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

427
Cargo.lock generated Normal file
View File

@@ -0,0 +1,427 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "ark-ff"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"arrayvec",
"digest",
"educe",
"itertools",
"num-bigint",
"num-traits",
"paste",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "ark-ff-macros"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3"
dependencies = [
"num-bigint",
"num-traits",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ark-poly"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27"
dependencies = [
"ahash",
"ark-ff",
"ark-serialize",
"ark-std",
"educe",
"fnv",
"hashbrown",
]
[[package]]
name = "ark-serialize"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7"
dependencies = [
"ark-serialize-derive",
"ark-std",
"arrayvec",
"digest",
"num-bigint",
]
[[package]]
name = "ark-serialize-derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ark-std"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a"
dependencies = [
"num-traits",
"rand",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"crypto-common",
]
[[package]]
name = "educe"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417"
dependencies = [
"enum-ordinalize",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "enum-ordinalize"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5"
dependencies = [
"enum-ordinalize-derive",
]
[[package]]
name = "enum-ordinalize-derive"
version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "mdsecheck"
version = "0.1.0"
dependencies = [
"ark-ff",
"ark-poly",
"rand",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

9
Cargo.toml Normal file
View File

@@ -0,0 +1,9 @@
[package]
name = "mdsecheck"
version = "0.1.0"
edition = "2021"
[dependencies]
ark-ff = { version = "0.5.0", default-features = false, features = ["asm"] }
ark-poly = "0.5.0"
rand = "0.8.5"

77
src/lib.rs Normal file
View File

@@ -0,0 +1,77 @@
use ark_ff::PrimeField;
use ark_poly::{polynomial::univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
use rand::Rng;
use std::collections::HashSet;
pub mod mat;
pub mod num;
pub mod poly;
pub fn random_cauchy<F: PrimeField>(n: u32, r: &mut (impl Rng + ?Sized)) -> Option<Vec<Vec<F>>> {
if (n == 0) || (F::MODULUS < F::BigInt::from(n as u64 * 2)) {
return None;
}
let n = n as usize;
let mut d = HashSet::with_capacity(2 * n);
for _ in 0..2 * n {
while !d.insert(F::rand(r)) {}
}
let mut m = Vec::with_capacity(n);
for y in d.iter().skip(n) {
let mut v = Vec::with_capacity(n);
for x in d.iter().take(n) {
v.push((*x - y).inverse().unwrap());
}
m.push(v);
}
Some(m)
}
pub fn secure_rounds<F: PrimeField>(a: &[impl AsRef<[F]>], l: usize) -> Option<usize> {
if l == 0 {
return None;
}
let n: usize = a.len();
let mut m = Vec::<Vec<F>>::with_capacity(n);
m.push(vec![F::ONE; n]);
for i in 0..n - 1 {
m.push(mat::product_vector(a, &m[i])?);
}
let b = mat::product_vector(a, &m[n - 1])?;
for y in 0..n {
for x in 0..y {
(m[y][x], m[x][y]) = (m[x][y], m[y][x]);
}
}
let mut s = mat::unique_solution(&m, &b)?;
s.iter_mut().for_each(|e| *e = -*e);
s.push(F::ONE);
let c = DensePolynomial::<F>::from_coefficients_vec(s);
let f = num::prime_divisors(n as u32)
.into_iter()
.map(|e| n / e as usize)
.collect::<HashSet<usize>>();
let mut y: Vec<DensePolynomial<F>> = Vec::<DensePolynomial<F>>::with_capacity(f.len());
let x = poly::new(&[0u64, 1u64]);
let mut r = x.clone();
for d in 1..=n / 2 {
r = poly::power_modulo(&r, F::characteristic(), &c)?;
if poly::nonmonic_gcd(&(&r - &x), &c).degree() > 0 {
return None;
}
if f.contains(&d) {
y.push(r.clone());
}
}
let (mut g, mut h) = (x.clone(), y.clone());
for i in 2..=l {
g = poly::reduced_modulo(&(&g * &x), &c)?;
for (v, u) in h.iter_mut().zip(y.iter()) {
*v = poly::reduced_modulo(&(&*v * u), &c)?;
if *v == g {
return Some(i - 1);
}
}
}
Some(l)
}

94
src/mat.rs Normal file
View File

@@ -0,0 +1,94 @@
use ark_ff::Field;
pub fn product_vector<F: Field>(a: &[impl AsRef<[F]>], b: &[F]) -> Option<Vec<F>> {
let k = b.len();
if (k == 0) || a.is_empty() {
// Either the matrix or the vector is empty
return None;
}
if a.iter().any(|s| s.as_ref().len() != k) {
// The arguments are not a matrix-vector pair for which the product is defined
return None;
}
let mut v = Vec::<F>::with_capacity(a.len());
for s in a.iter() {
let s = s.as_ref();
v.push((0..k).map(|i| s[i] * b[i]).sum());
}
Some(v)
}
pub fn product_matrix<F: Field>(
a: &[impl AsRef<[F]>],
b: &[impl AsRef<[F]>],
) -> Option<Vec<Vec<F>>> {
let k = b.len();
if (k == 0) || a.is_empty() {
// Some matrix is empty
return None;
}
let c = b[0].as_ref().len();
if a.iter().any(|s| s.as_ref().len() != k) || (0..k).any(|y| b[y].as_ref().len() != c) {
// The arguments are not matrices for which the product is defined
return None;
}
let mut m = Vec::<Vec<F>>::with_capacity(a.len());
for s in a.iter() {
let mut l = Vec::<F>::with_capacity(c);
let s = s.as_ref();
for x in 0..c {
l.push((0..k).map(|i| s[i] * b[i].as_ref()[x]).sum());
}
m.push(l);
}
Some(m)
}
pub fn unique_solution<F: Field>(a: &[impl AsRef<[F]>], b: &[F]) -> Option<Vec<F>> {
let n = a.len();
if n == 0 {
// The matrix is empty
return None;
}
if b.len() != n {
// The heights of the matrix and column vector are different
return None;
}
let mut m = Vec::<Vec<F>>::with_capacity(n);
for (r, v) in a.iter().zip(b.iter()) {
let r = r.as_ref();
if r.len() != n {
// The first argument is not a square matrix
return None;
}
m.push([r, &[*v][..]].concat());
}
for r in 0..n {
if m[r][r] == F::ZERO {
if let Some(p) = (r + 1..n).find(|y| m[*y][r] != F::ZERO) {
m.swap(r, p);
} else {
// The matrix is singular
return None;
}
}
let c = m[r][r];
m[r][r] = F::ONE;
for x in r + 1..=n {
m[r][x] /= c;
}
for y in r + 1..n {
let c = m[y][r];
m[y][r] = F::ZERO;
for x in r + 1..=n {
m[y][x] = m[y][x] - c * m[r][x];
}
}
}
for r in (1..n).rev() {
for y in 0..r {
m[y][n] = m[y][n] - m[y][r] * m[r][n];
}
}
Some((0..n).map(|y| m[y][n]).collect())
}

45
src/num.rs Normal file
View File

@@ -0,0 +1,45 @@
pub fn reversed_bits(n: &[u64]) -> impl Iterator<Item = bool> + '_ {
n.iter()
.rev()
.copied()
.skip_while(|c| *c == 0)
.map(|c| c.reverse_bits())
.flat_map(|c| (0..64).map(move |b| c & (1 << b) != 0))
.skip_while(|b| !b)
}
pub fn prime_divisors(mut n: u32) -> Vec<u32> {
if n < 2 {
return vec![];
}
let mut p = Vec::with_capacity(n.ilog2() as usize);
if n & 1 == 0 {
p.push(2);
n >>= n.trailing_zeros();
}
fn extract(f: u32, m: &mut u32, l: &mut Vec<u32>) {
l.push(f);
*m /= f;
while *m % f == 0 {
*m /= f;
}
}
if n % 3 == 0 {
extract(3, &mut n, &mut p);
}
fn sqrt(v: u32) -> u32 {
(v as f64).sqrt().round() as u32
}
let (mut d, mut s, mut b) = (5u32, 2u32, sqrt(n));
while d <= b {
if n % d == 0 {
extract(d, &mut n, &mut p);
b = sqrt(n);
}
(d, s) = (d + s, s ^ 6);
}
if n > 1 {
p.push(n)
}
p
}

59
src/poly.rs Normal file
View File

@@ -0,0 +1,59 @@
use ark_ff::{PrimeField, Zero};
use ark_poly::{
polynomial::univariate::{DenseOrSparsePolynomial, DensePolynomial},
DenseUVPolynomial, Polynomial,
};
pub fn new<F: PrimeField>(c: &[impl Into<F> + Clone]) -> DensePolynomial<F> {
DensePolynomial::from_coefficients_vec(c.iter().map(|e| e.clone().into()).collect())
}
pub fn reduced_modulo<F: PrimeField>(
p: &DensePolynomial<F>,
m: &DensePolynomial<F>,
) -> Option<DensePolynomial<F>> {
// This check is to avoid a "divide_with_q_and_r" panic, since
// for some reason "divide_with_q_and_r" never returns None
if m.is_zero() {
return None;
}
Some(
DenseOrSparsePolynomial::from(p)
.divide_with_q_and_r(&DenseOrSparsePolynomial::from(m))?
.1,
)
}
pub fn power_modulo<F: PrimeField>(
p: &DensePolynomial<F>,
e: &[u64],
m: &DensePolynomial<F>,
) -> Option<DensePolynomial<F>> {
let p = reduced_modulo(p, m)?;
let mut r = new(&[(m.degree() > 0) as u64]);
for b in crate::num::reversed_bits(e) {
r = reduced_modulo(&(&r * &r), m)?;
if b {
r = reduced_modulo(&(&r * &p), m)?;
}
}
Some(r)
}
pub fn nonmonic_gcd<F: PrimeField>(
a: &DensePolynomial<F>,
b: &DensePolynomial<F>,
) -> DensePolynomial<F> {
let mut a = match reduced_modulo(a, b) {
Some(r) => r,
None => return a.clone(),
};
let mut b = match reduced_modulo(b, &a) {
Some(r) => r,
None => return b.clone(),
};
while let Some(r) = reduced_modulo(&a, &b) {
(a, b) = (b, r);
}
a
}