qfall-math 0.1.1

Mathematical foundations for rapid prototyping of lattice-based cryptography
Documentation
// Copyright © 2024 Marcel Luca Schmidt
//
// This file is part of qFALL-math.
//
// qFALL-math is free software: you can redistribute it and/or modify it under
// the terms of the Mozilla Public License Version 2.0 as published by the
// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.

//! This module contains all options to convert a matrix of type
//! [`MatPolynomialRingZq`] into a [`String`].

use super::MatPolynomialRingZq;
use crate::macros::for_others::implement_for_owned;

impl From<&MatPolynomialRingZq> for String {
    /// Converts a [`MatPolynomialRingZq`] into its [`String`] representation.
    ///
    /// Parameters:
    /// - `value`: specifies the matrix that will be represented as a [`String`]
    ///
    /// Returns a [`String`] of the form `"[[poly_1, poly_2, poly_3],[poly_4, poly_5, poly_6]] / poly_7 mod q"`.
    ///
    /// # Examples
    /// ```
    /// use qfall_math::integer_mod_q::MatPolynomialRingZq;
    /// use std::str::FromStr;
    /// let matrix = MatPolynomialRingZq::from_str("[[2  2 2, 1  2],[0, 1  3]] / 2  4 1 mod 3").unwrap();
    ///
    /// let string: String = matrix.into();
    /// ```
    fn from(value: &MatPolynomialRingZq) -> Self {
        value.to_string()
    }
}

implement_for_owned!(MatPolynomialRingZq, String, From);

impl MatPolynomialRingZq {
    /// Outputs the matrix as a [`String`], where the upper leftmost `nr_printed_rows x nr_printed_columns`
    /// submatrix is output entirely as well as the corresponding entries in the last column and row of the matrix.
    ///
    /// Parameters:
    /// - `nr_printed_rows`: defines the number of rows of the upper leftmost matrix that are printed entirely
    /// - `nr_printed_columns`: defines the number of columns of the upper leftmost matrix that are printed entirely
    ///
    /// Returns a [`String`] representing the abbreviated matrix.
    ///
    /// # Example
    /// ```
    /// use qfall_math::integer::MatZ;
    /// let matrix = MatZ::identity(10, 10);
    ///
    /// println!("Matrix: {}", matrix.pretty_string(2, 2));
    /// // outputs the following:
    /// // Matrix: [
    /// //   [1, 0, , ..., 0],
    /// //   [0, 1, , ..., 0],
    /// //   [...],
    /// //   [0, 0, , ..., 1]
    /// // ]
    /// ```
    pub fn pretty_string(&self, nr_printed_rows: u64, nr_printed_columns: u64) -> String {
        let mut result = crate::utils::parse::partial_string(
            &self.get_representative_least_nonnegative_residue(),
            nr_printed_rows,
            nr_printed_columns,
        );
        result.push_str(&format!(" mod {}", self.modulus));
        result
    }
}

#[cfg(test)]
mod test_to_string {
    use crate::integer_mod_q::MatPolynomialRingZq;
    use std::str::FromStr;

    // Most tests are omitted, since the [`Display`](std::fmt::Display) trait
    // is derived and therefor already tested.

    /// Tests whether a roundtrip works correctly.
    #[test]
    fn roundtrip() {
        let cmp =
            MatPolynomialRingZq::from_str("[[1  2, 1  1, 0],[1  5, 1  6, 1  7]] / 2  1 1 mod 11")
                .unwrap();

        assert_eq!(
            "[[1  2, 1  1, 0],[1  5, 1  6, 1  7]] / 2  1 1 mod 11",
            cmp.to_string()
        )
    }

    /// Tests whether the matrix is correctly reduced.
    #[test]
    fn reduced() {
        let cmp =
            MatPolynomialRingZq::from_str("[[2  2 2, 1  1, 0],[1  5, 1  6, 1  7]] / 2  4 1 mod 3")
                .unwrap();

        assert_eq!(
            "[[0, 1  1, 0],[1  2, 0, 1  1]] / 2  1 1 mod 3",
            cmp.to_string()
        )
    }
}