ferric_crypto_lib 0.2.7

A library for Ferric Crypto
Documentation
/// Transposes a matrix.
///
/// This function takes a matrix represented as a 1D vector, along with the number of rows and columns,
/// and returns a new matrix (also represented as a 1D vector) where the rows and columns are swapped.
///
/// # Arguments
///
/// * `matrix` - A reference to a `Vec<usize>` that holds the original matrix. The matrix is assumed to be
///              in row-major order, i.e., all elements of the first row come first, followed by the second row, etc.
/// * `rows` - The number of rows in the original matrix.
/// * `cols` - The number of columns in the original matrix.
///
/// # Returns
///
/// * A `Vec<Vec<usize>>` representing the transposed matrix. Each inner vector represents a row in the transposed matrix.
///
/// # Example
///
/// ```
/// # use ferric_crypto_lib::utils::matrix_functions::transpose_matrix;
///
/// let matrix = vec![1, 2, 3, 4, 5, 6];
/// let rows = 2;
/// let cols = 3;
/// let transposed = transpose_matrix(&matrix, rows, cols);
///
/// println!("{:?}", transposed);
/// ```
///
/// This will print `[[1, 4], [2, 5], [3, 6]]`.
pub fn transpose_matrix(matrix: &[usize], rows: usize, cols: usize) -> Vec<Vec<usize>> {
    (0..cols)
        .map(|col| (0..rows).map(|row| matrix[row * cols + col]).collect())
        .collect()
}

/// Reshapes a 1D vector into a 2D matrix.
///
/// This function takes a 1D vector and the desired number of rows and columns,
/// and returns a new 2D matrix where each row is a vector of elements from the original vector.
///
/// # Arguments
///
/// * `vec` - A `Vec<usize>` that holds the original 1D vector.
/// * `rows` - The desired number of rows in the output matrix.
/// * `cols` - The desired number of columns in each row of the output matrix.
///
/// # Returns
///
/// * A `Vec<Vec<usize>>` representing the reshaped matrix.
/// Each inner vector represents a row in the reshaped matrix.
///
/// # Example
///
/// ```
/// # use ferric_crypto_lib::utils::matrix_functions::reshape_to_matrix;
///
/// let vec = vec![1, 2, 3, 4, 5, 6];
/// let rows = 2;
/// let cols = 3;
/// let reshaped = reshape_to_matrix(vec, rows, cols);
///
/// println!("{:?}", reshaped);
/// ```
///
/// This will print `[[1, 2, 3], [4, 5, 6]]`.
pub fn reshape_to_matrix(vec: Vec<usize>, rows: usize, cols: usize) -> Vec<Vec<usize>> {
    vec.chunks(cols).map(|chunk| chunk.to_vec()).collect()
}

// --------------------------------------------------------------------------------------

use nalgebra::*;

// maybe implement EEA here and use nalgebras gcd function
fn modular_inverse(x: f32, modulus: i32) -> Option<f32> {
    for i in 1..modulus {
        if (i as f32 * x % modulus as f32 + modulus as f32) % modulus as f32 == 1.0 {
            return Some(i as f32);
        }
    }
    None
}

fn minor(matrix: &DMatrix<f32>, row: usize, col: usize) -> f32 {
    let submatrix = matrix.clone().remove_row(row).remove_column(col);
    submatrix.determinant()
}

fn adjugate(matrix: &DMatrix<f32>) -> DMatrix<f32> {
    let cofactor_matrix = matrix.map_with_location(|i, j, _| {
        let sign = if (i + j) % 2 == 0 { 1.0 } else { -1.0 };
        sign * minor(matrix, i, j)
    });

    cofactor_matrix.transpose()
}

#[test]
fn test_things() {
    let m = Matrix3::new(5.0, 17.0, 6.0, 2.0, 21.0, 14.0, 19.0, 3.0, 11.0);

    let determinant = m.determinant(); // Calculate the determinant

    // Adjust the determinant for modulo 28
    let det_mod: f32 = (determinant % 28.0 + 28.0) % 28.0;
    dbg!(&determinant);

    // Find the modular inverse of the determinant
    match modular_inverse(det_mod, 28) {
        Some(det_mod_inverse) => {
            // Manually compute the adjugate matrix
            let adjugate = Matrix3::new(
                m[(1, 1)] * m[(2, 2)] - m[(1, 2)] * m[(2, 1)],
                -(m[(1, 0)] * m[(2, 2)] - m[(1, 2)] * m[(2, 0)]),
                m[(1, 0)] * m[(2, 1)] - m[(1, 1)] * m[(2, 0)],
                -(m[(0, 1)] * m[(2, 2)] - m[(0, 2)] * m[(2, 1)]),
                m[(0, 0)] * m[(2, 2)] - m[(0, 2)] * m[(2, 0)],
                -(m[(0, 0)] * m[(2, 1)] - m[(0, 1)] * m[(2, 0)]),
                m[(0, 1)] * m[(1, 2)] - m[(0, 2)] * m[(1, 1)],
                -(m[(0, 0)] * m[(1, 2)] - m[(0, 2)] * m[(1, 0)]),
                m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)],
            )
            .transpose();

            // Apply the modular inverse to the adjugate and then apply modulo 28
            let modular_inverse = adjugate.map(|x| ((x * det_mod_inverse) % 28.0 + 28.0) % 28.0);

            println!("Modular Inverse:\n{}", modular_inverse);
        }
        None => println!("Matrix is not invertible in mod 28"),
    }

    let m = Matrix3::new(5.0, 17.0, 6.0, 2.0, 21.0, 14.0, 19.0, 3.0, 11.0);
    let m = DMatrix::from_row_slice(3, 3, m.as_slice());

    let adj = adjugate(&m);
    println!("Adjugate Matrix:\n{}", &adj);

    let adj_trans = adj.transpose();
    println!("Transposed Adjugate Matrix:\n{}", &adj_trans);

    let determinant = m.determinant(); // Calculate the determinant

    // Adjust the determinant for modulo 28
    let det_mod: f32 = (determinant % 28.0 + 28.0) % 28.0;
    dbg!(&determinant);

    // Find the modular inverse of the determinant
    match modular_inverse(det_mod, 28) {
        Some(det_mod_inverse) => {
            // Apply the modular inverse to the adjugate and then apply modulo 28
            let modular_inverse = adj_trans.map(|x| ((x * det_mod_inverse) % 28.0 + 28.0) % 28.0);

            println!("Modular Inverse:\n{}", modular_inverse);
        }
        None => println!("Matrix is not invertible in mod 28"),
    }

    println!("===================================================");

    let m = Matrix2::new(6.0, 25.0, 3.0, 11.0);

    let m = DMatrix::from_row_slice(2, 2, m.as_slice());

    let adj = adjugate(&m);
    let adj_trans = adj.transpose();

    let determinant = m.determinant(); // Calculate the determinant

    // Adjust the determinant for modulo 28
    let det_mod: f32 = (determinant % 28.0 + 28.0) % 28.0;

    // Find the modular inverse of the determinant
    match modular_inverse(det_mod, 28) {
        Some(det_mod_inverse) => {
            let modular_inverse = adj_trans.map(|x| ((x * det_mod_inverse) % 28.0 + 28.0) % 28.0);

            println!("Modular Inverse:\n{}", modular_inverse);
        }
        None => println!("Matrix is not invertible in mod 28"),
    }
}