qFALL-math advanced types

For all basic types Z, Zq and Q, there exists a matrix MatZ, MatZq and MatQ. They can be instantiated from strings or as zero matrices with their entries set manually with the functions set_entry(), set_row and set_column. There also exist polynomials like PolyZ, PolyZq and PolyQ, which can be instantiated from strings or as zero polynomials with their coefficients set manually with the function set_coeff(). Furthermore, we provide ring elements like PolynomialRingZq, which can be instantiated from strings or their components. Matrices, polynomials and rings support all common arithmetic operations, among other functionalities.

These three advanced types and their functionalities are presented in the following sections with examples of how to use them.

Instantiate advanced types

MatZ, MatZq and MatQ can be instantiated from strings or as 0 matrices.

use qfall_math::{integer::MatZ, integer_mod_q::MatZq, rational::MatQ};
use std::str::FromStr;

fn matrix_instantiations() {
    // instantiations using new
    // the first number is the number of rows and the second one the number of columns
    let matz = MatZ::new(5, 10);
    let matzq = MatZq::new(5, 10, 13);
    let matq = MatQ::new(5, 10);

    // instantiations using strings
    // the content of a matrix is written in square brackets and
    // one row of the matrix consists of numbers divided by commas in a square bracket
    let matz = MatZ::from_str("[[1,2],[3,4]]").unwrap();
    let matzq = MatZq::from_str("[[1,2],[3,4]] mod 5").unwrap();
    let matq = MatQ::from_str("[[1/2,2],[3/4,4]]").unwrap();

    // instantiations using components
    let matz = MatZ::from(&matzq);
    let matq = MatQ::from(&matz);
}

PolyZ, PolyZq and PolyQ can be instantiated from strings and their components.

use qfall_math::{
    integer::PolyOverZ,
    integer_mod_q::{Modulus, PolyOverZq},
    rational::PolyOverQ,
};
use std::str::FromStr;

fn polynomial_instantiations() {
    // instantiations using strings
    // the first number is the number of coefficients in the polynomial,
    // which is followed by the coefficients in ascending order
    let polyz = PolyOverZ::from_str("4  0 1 2 3").unwrap();
    let polyzq = PolyOverZq::from_str("4  0 1 -2 3 mod 42").unwrap();
    let polyq = PolyOverQ::from_str("5  0 1/3 2/10 -3/2 1").unwrap();

    // instantiations using components
    let modulus = Modulus::from_str("100").unwrap();

    let polyzq = PolyOverZq::from(&modulus);
    let polyzq = PolyOverZq::from((&polyz, &modulus));

    let polyq = PolyOverQ::from(&polyz);
}

PolynomialRingZq can be instantiated from strings or its components.

use qfall_math::integer::PolyOverZ;
use qfall_math::integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq};
use std::str::FromStr;

fn ring_instantiations() {
    // instantiations using components
    let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
    let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();

    let poly_ring = PolynomialRingZq::from((&poly, &modulus));
}

Manipulation of advanced types

Entries from matrices can be set manually with the functions set_entry(), set_row() and set_column(). Their entries/rows/columns can be swapped with the functions swap_entries()/swap_row()/swap_column(). Rows/Columns of matrices can be reversed with the functions reverse_rows()/reverse_columns() and sorted with the functions sort_by_rows()/sort_by_columns().

Coefficients of polynomials and ring elements can be set manually with the function set_coeff().

use qfall_math::{
    integer::{MatZ, PolyOverZ},
    traits::*,
};
use std::str::FromStr;

fn manipulation() {
    let mut matz_1 = MatZ::from_str("[[1,2,3],[4,5,6]]").unwrap();
    let matz_2 = MatZ::from_str("[[5,2,7],[4,2,1]]").unwrap();
    let mut polyz = PolyOverZ::from_str("4  -1 0 1 1").unwrap();

    matz_1.set_entry(1, 2, 8).unwrap();
    matz_1.set_row(0, &matz_2, 1).unwrap();

    polyz.set_coeff(2, 6).unwrap();
}

Note that for all set_*() functions, there is a corresponding get_*() function.

MatZq, PolyZq, PolynomialRingZq and their Moduli

Just like Zq, the advanced types MatZq, PolyZq and PolynomialRingZq have special roles since they do not only contain a value but also a context object represented by their moduli. A modulus object is of type Modulus or in the case of a PolynomialRingZq of type ModulusPolynomialRingZq.

The modulus Modulus can be instantiated from a Z greater or equal to two, and the modulus ModulusPolynomialRingZq can be instantiated from a PolyZq.

use qfall_math::integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq};
use std::str::FromStr;

fn instantiate_moduli() {
    let modulus = Modulus::from(42);

    let polyzq = PolyOverZq::from_str("4  1 0 0 1 mod 17").unwrap();
    let modulus_poly = ModulusPolynomialRingZq::from(&polyzq);
}

Both moduli can be shared among different values and, if shared, reduce runtime and reduce storage usage, since only the reference counter goes up, and the modulus is not cloned.

use qfall_math::{
    integer::MatZ,
    integer_mod_q::{MatZq, Modulus, Zq},
};
use std::str::FromStr;

fn shared_moduli() {
    let modulus = Modulus::from(42);
    let matz_1 = MatZ::from_str("[[1,2,3],[4,5,6]]]").unwrap();
    let matz_2 = MatZ::from_str("[[17,42],[89, 100]]]").unwrap();

    let zq_1 = Zq::from((17, 42));
    let zq_2 = Zq::from((24, 42));

    let matzq_1 = MatZq::from_mat_z_modulus(&matz_1, &modulus);
    let matzq_2 = MatZq::from_mat_z_modulus(&matz_2, &modulus);
}

Matrices as Vectors

We do not have explicit vector types like VecZ, VecZq and VecQ, but all matrices can serve as vectors if they have the correct dimensions. So a MatZ matrix with dimensions 1 x n is a row vector and a matrix with dimensions n x 1 a column vector. This property can be checked with the function is_vector().

use qfall_math::{
    integer::{MatPolyOverZ, MatZ},
    integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
};
use std::str::FromStr;

fn vectors() {
    let vecz = MatZ::from_str("[[1/2,2,3/4]]").unwrap();
    let poly_vec = MatPolyOverZ::from_str("[[4  -1 0 1 1],[2  12 4]]").unwrap();
    let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 42").unwrap();
    let poly_ring_vec =
        MatPolynomialRingZq::from_poly_over_z_modulus_polynomial_ring_zq(&poly_vec, &modulus);

    let is_vector = vecz.is_vector();
    let is_vector = poly_vec.is_vector();
    let is_vector = poly_ring_vec.is_vector();

    let dot_product = vecz.dot_product(&vecz);
    let norm = vecz.norm_eucl_sqrd();
}

Note that matrices with dimensions 1 x 1 are seen as both row and column vectors.

Converting types

All reasonable types can be converted between one another, e.g. we can define a MatQ from a MatZ or a PolyQ from a PolyZ.

use qfall_math::{
    integer::{MatZ, PolyOverZ},
    rational::{MatQ, PolyOverQ},
};
use std::str::FromStr;

fn conversions() {
    let matz = MatZ::from_str("[[1,2],[3,4]]").unwrap();
    let matq = MatQ::from(&matz);

    let polyz = PolyOverZ::from_str("4  1 2 3 4").unwrap();
    let polyq = PolyOverQ::from(&polyz);
}

Arithmetics

All advanced types (except moduli) support basic arithmetics. Among these are multiplication, addition and subtraction.

use qfall_math::{
    integer::PolyOverZ,
    integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
    rational::MatQ,
};
use std::str::FromStr;

fn basic_arithmetics() {
    let matq = MatQ::from_str("[[1/2,2,3/4],[4,5/10,6]]").unwrap();
    let polyz = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
    let polyz_2 = PolyOverZ::from_str("4  -1 0 1 2").unwrap();
    let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 42").unwrap();
    let poly_ring = PolynomialRingZq::from((&polyz, &modulus));

    let add = &matq + &matq;
    let sub = &polyz_2 - &polyz;
    let mul = &poly_ring * &poly_ring;
}

Printing your Results

You can print the values of all advanced types with the print! or println! command or convert them into strings with .to_string().

use qfall_math::{
    integer::PolyOverZ,
    integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
    rational::MatQ,
};
use std::str::FromStr;

fn print() {
    let matq = MatQ::from_str("[[1/2,2,3/4],[4,5/10,6]]").unwrap();
    let polyz = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
    let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 42").unwrap();
    let poly_ring = PolynomialRingZq::from((&polyz, &modulus));

    // print them directly
    println!("{matq}");
    println!("{polyz}");
    println!("{modulus}");
    println!("{poly_ring}");

    // turn them into a string first
    let matq_string = matq.to_string();
    let polyz_string = polyz.to_string();
    let modulus_string = modulus.to_string();
    let poly_ring_string = poly_ring.to_string();

    println!("{}", matq_string);
    println!("{}", polyz_string);
    println!("{}", modulus_string);
    println!("{}", poly_ring_string);
}