Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "qfall-math"
version = "0.1.1"
version = "0.1.2"
edition = "2024"
rust-version = "1.87" # due to wit_bindgen dependency
description = "Mathematical foundations for rapid prototyping of lattice-based cryptography"
Expand All @@ -15,7 +15,7 @@ autobenches = false
[dependencies]
criterion = { version = "0.8", features = ["html_reports"] }
flint-sys = "0.7"
libc = "0"
libc = "0.2"
paste = "1"
rand = "0.10"
rand_distr = "0.6"
Expand All @@ -26,7 +26,7 @@ string-builder = "0.2"
thiserror = "2"
lazy_static = "1"
probability = "0.20"
derive_more = { version = "2.1", features = ["display"] }
derive_more = { version = "2", features = ["display"] }

[profile.bench]
debug = true
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ let vec_t = &mat_a * &vec_e;
let vec_b = vec_s.transpose() * mat_a + vec_e.transpose();
```

## SemVer and Backward Compatibility
While this library is not stable yet, i.e. pre-version 1.0.0, we may introduce API-breaking changes in MINOR version updates.
Therefore, we recommend to fix the used version `version = "0.y"` in your `Cargo.toml`.

## Bugs
Please report bugs through the [GitHub issue tracker](https://github.com/qfall/math/issues).

Expand Down
46 changes: 45 additions & 1 deletion src/integer/mat_poly_over_z/norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::MatPolyOverZ;
use crate::{
integer::Z,
rational::Q,
traits::{MatrixDimensions, MatrixGetSubmatrix},
traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
};

impl MatPolyOverZ {
Expand Down Expand Up @@ -89,6 +89,31 @@ impl MatPolyOverZ {
}
max_norm
}

/// Outputs the hamming weight of `self`, i.e. it computes the sum of all non-zero
/// coefficients in each polynomial in the matrix.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normally, the hamming weight is only defined as the number of non-zero coefficients, and not the sum of the non-zero coefficients. Typically the HW is also used in cases of binary vectors, so that could be a reason. Anyways, I think this definition as is, is confusing in regards to usage

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition is wrong. I meant to say "the sum of number of non-zero coefficients..." to be explicit. However, the updated doc comment is precise.

///
/// # Examples
/// ```
/// use qfall_math::integer::MatPolyOverZ;
/// use std::str::FromStr;
///
/// let mat = MatPolyOverZ::from_str("[[2 2 1, 2 3 0],[1 2, 0]]").unwrap();
///
/// let hamming_weight = mat.hamming_weight();
///
/// assert_eq!(4, hamming_weight);
/// ```
pub fn hamming_weight(&self) -> i64 {
let mut hamming_weight = 0;
for row in 0..self.get_num_rows() {
for col in 0..self.get_num_columns() {
let entry = unsafe { self.get_entry_unchecked(row, col) };
hamming_weight += entry.hamming_weight();
}
}
hamming_weight
}
}

#[cfg(test)]
Expand Down Expand Up @@ -131,3 +156,22 @@ mod test_matrix_norms {
assert_eq!(Z::from(5), infty_norm);
}
}

#[cfg(test)]
mod test_hamming_weight {
use super::MatPolyOverZ;
use std::str::FromStr;

/// Ensures that the hamming weight is computed correctly.
#[test]
fn hamming_weight() {
let mat0 = MatPolyOverZ::new(3, 4);
let mat1 = MatPolyOverZ::from_str("[[1 -2, 2 3 2],[2 2 0, 1 -5],[1 -2, 0]]").unwrap();

let hw0 = mat0.hamming_weight();
let hw1 = mat1.hamming_weight();

assert_eq!(0, hw0);
assert_eq!(6, hw1);
}
}
48 changes: 47 additions & 1 deletion src/integer/mat_z/norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::MatZ;
use crate::{
integer::Z,
rational::Q,
traits::{MatrixDimensions, MatrixGetSubmatrix},
traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
};

impl MatZ {
Expand Down Expand Up @@ -89,6 +89,33 @@ impl MatZ {
}
max_norm
}

/// Outputs the hamming weight of `self`, i.e. it returns the number of
/// non-zero entries in the matrix.
///
/// # Examples
/// ```
/// use qfall_math::integer::MatZ;
/// use std::str::FromStr;
///
/// let mat = MatZ::from_str("[[2, 3],[2, 0]]").unwrap();
///
/// let hamming_weight = mat.hamming_weight();
///
/// assert_eq!(3, hamming_weight);
/// ```
pub fn hamming_weight(&self) -> i64 {
let mut hamming_weight = 0;
for row in 0..self.get_num_rows() {
for col in 0..self.get_num_columns() {
let entry = unsafe { self.get_entry_unchecked(row, col) };
if !entry.is_zero() {
hamming_weight += 1;
}
}
}
hamming_weight
}
}

#[cfg(test)]
Expand Down Expand Up @@ -126,3 +153,22 @@ mod test_matrix_norms {
assert_eq!(Z::from(5), infty_norm);
}
}

#[cfg(test)]
mod test_hamming_weight {
use super::MatZ;
use std::str::FromStr;

/// Ensures that the hamming weight is computed correctly.
#[test]
fn hamming_weight() {
let mat0 = MatZ::new(10, 8);
let mat1 = MatZ::from_str("[[-2, 3],[2, -5],[-2, 0]]").unwrap();

let hw0 = mat0.hamming_weight();
let hw1 = mat1.hamming_weight();

assert_eq!(0, hw0);
assert_eq!(5, hw1);
}
}
65 changes: 65 additions & 0 deletions src/integer/poly_over_z/norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use crate::{
integer::{PolyOverZ, Z},
rational::Q,
traits::{GetCoefficient, Pow},
};
use std::cmp::max;
Expand Down Expand Up @@ -42,6 +43,26 @@ impl PolyOverZ {
res
}

/// Returns the Euclidean norm or 2-norm of the given polynomial.
/// The Euclidean norm for a polynomial is obtained by treating the coefficients
/// of the polynomial as a vector and then applying the standard Euclidean norm.
///
/// # Examples
/// ```
/// use qfall_math::{integer::PolyOverZ, rational::Q};
/// use std::str::FromStr;
///
/// let poly = PolyOverZ::from_str("1 3").unwrap();
///
/// let norm = poly.norm_eucl();
///
/// // sqrt(3^2) = 3
/// assert_eq!(Q::from(3), norm);
/// ```
pub fn norm_eucl(&self) -> Q {
self.norm_eucl_sqrd().sqrt()
}

/// Returns the infinity norm or the maximal absolute value of a
/// coefficient of the given polynomial.
/// The infinity norm for a polynomial is obtained by treating the coefficients
Expand All @@ -68,6 +89,31 @@ impl PolyOverZ {
}
res
}

/// Outputs the hamming weight of `self`, i.e. it returns the number of
/// non-zero coefficients in the polynomial.
///
/// # Examples
/// ```
/// use qfall_math::integer::PolyOverZ;
/// use std::str::FromStr;
///
/// let poly = PolyOverZ::from_str("5 1 2 3 0 4").unwrap();
///
/// let hamming_weight = poly.hamming_weight();
///
/// assert_eq!(4, hamming_weight);
/// ```
pub fn hamming_weight(&self) -> i64 {
let mut hamming_weight = 0;
for i in 0..=self.get_degree() {
let coeff = unsafe { self.get_coeff_unchecked(i) };
if !coeff.is_zero() {
hamming_weight += 1;
}
}
hamming_weight
}
}

#[cfg(test)]
Expand Down Expand Up @@ -139,3 +185,22 @@ mod test_norm_infty {
assert_eq!(poly_2.norm_infty(), Z::from(u64::MAX));
}
}

#[cfg(test)]
mod test_hamming_weight {
use super::PolyOverZ;
use std::str::FromStr;

/// Ensures that the hamming weight is computed correctly.
#[test]
fn hamming_weight() {
let poly0 = PolyOverZ::default();
let poly1 = PolyOverZ::from_str("6 0 0 2 3 4 5").unwrap();

let hw0 = poly0.hamming_weight();
let hw1 = poly1.hamming_weight();

assert_eq!(0, hw0);
assert_eq!(4, hw1);
}
}
54 changes: 52 additions & 2 deletions src/integer_mod_q/mat_polynomial_ring_zq/norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

use super::MatPolynomialRingZq;
use crate::{
integer::Z,
integer::{PolyOverZ, Z},
rational::Q,
traits::{MatrixDimensions, MatrixGetSubmatrix},
traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
};

impl MatPolynomialRingZq {
Expand Down Expand Up @@ -96,6 +96,33 @@ impl MatPolynomialRingZq {
}
max_norm
}

/// Outputs the hamming weight of `self`, i.e. it computes the sum of all non-zero
/// coefficients in each polynomial in the matrix.
///
/// # Examples
/// ```
/// use qfall_math::{integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}, integer::{Z, MatPolyOverZ}};
/// use std::str::FromStr;
///
/// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 7").unwrap();
/// let mat = MatPolyOverZ::from_str("[[2 2 1, 2 3 0],[1 2, 0]]").unwrap();
/// let mat = MatPolynomialRingZq::from((&mat, &modulus));
///
/// let hamming_weight = mat.hamming_weight();
///
/// assert_eq!(4, hamming_weight);
/// ```
pub fn hamming_weight(&self) -> i64 {
let mut hamming_weight = 0;
for row in 0..self.get_num_rows() {
for col in 0..self.get_num_columns() {
let entry: PolyOverZ = unsafe { self.get_entry_unchecked(row, col) };
hamming_weight += entry.hamming_weight();
}
}
hamming_weight
}
}

#[cfg(test)]
Expand Down Expand Up @@ -145,3 +172,26 @@ mod test_matrix_norms {
assert_eq!(Z::from(3), infty_norm);
}
}

#[cfg(test)]
mod test_hamming_weight {
use super::MatPolynomialRingZq;
use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
use std::str::FromStr;

/// Ensures that the hamming weight is computed correctly.
#[test]
fn hamming_weight() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 8").unwrap();
let mat0 = MatPolyOverZ::new(3, 4);
let mat0 = MatPolynomialRingZq::from((&mat0, &modulus));
let mat1 = MatPolyOverZ::from_str("[[1 -2, 2 3 2],[2 2 0, 1 -5],[1 -2, 0]]").unwrap();
let mat1 = MatPolynomialRingZq::from((&mat1, &modulus));

let hw0 = mat0.hamming_weight();
let hw1 = mat1.hamming_weight();

assert_eq!(0, hw0);
assert_eq!(6, hw1);
}
}
49 changes: 48 additions & 1 deletion src/integer_mod_q/mat_zq/norm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
use super::MatZq;
use crate::{
integer::Z,
integer_mod_q::Zq,
rational::Q,
traits::{MatrixDimensions, MatrixGetSubmatrix},
traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
};

impl MatZq {
Expand Down Expand Up @@ -89,6 +90,33 @@ impl MatZq {
}
max_norm
}

/// Outputs the hamming weight of `self`, i.e. it returns the number of
/// non-zero entries in the matrix.
Comment thread
Marvin-Beckmann marked this conversation as resolved.
///
/// # Examples
/// ```
/// use qfall_math::integer_mod_q::MatZq;
/// use std::str::FromStr;
///
/// let mat = MatZq::from_str("[[2, 3],[2, 0]] mod 3").unwrap();
///
/// let hamming_weight = mat.hamming_weight();
///
/// assert_eq!(2, hamming_weight);
/// ```
pub fn hamming_weight(&self) -> i64 {
let mut hamming_weight = 0;
for row in 0..self.get_num_rows() {
for col in 0..self.get_num_columns() {
let entry: Zq = unsafe { self.get_entry_unchecked(row, col) };
if !entry.is_zero() {
hamming_weight += 1;
}
}
}
hamming_weight
}
}

#[cfg(test)]
Expand Down Expand Up @@ -126,3 +154,22 @@ mod test_matrix_norms {
assert_eq!(Z::from(3), infty_norm);
}
}

#[cfg(test)]
mod test_hamming_weight {
use super::MatZq;
use std::str::FromStr;

/// Ensures that the hamming weight is computed correctly.
#[test]
fn hamming_weight() {
let mat0 = MatZq::new(10, 8, 7);
let mat1 = MatZq::from_str("[[-2, 3],[2, -4],[-2, 0]] mod 4").unwrap();

let hw0 = mat0.hamming_weight();
let hw1 = mat1.hamming_weight();

assert_eq!(0, hw0);
assert_eq!(4, hw1);
}
}
Loading
Loading