Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
49 changes: 26 additions & 23 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ on:
push:
branches: [main]

permissions:
contents: read

# a new run for the same branch or pull request cancels the outdated run
concurrency:
group: ${{ github.workflow_ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
RUSTDOCFLAGS: "-Dwarnings"
Expand All @@ -12,29 +20,30 @@ jobs:
full_pipeline:
name: Full Pipeline
runs-on: ubuntu-latest
timeout-minutes: 90

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7

- name: Setup dtolnay/rust-toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: clippy, rustfmt

# load project cache to reduce compilation time
# The native FLINT library is compiled for the CPU of the runner it is built on.
# Hence, the cache may only be reused on runners with the same CPU (model and features).
- name: Determine CPU of the runner
id: cpu
run: |
grep -m1 'model name' /proc/cpuinfo
echo "hash=$({ grep -m1 'model name' /proc/cpuinfo; grep -m1 '^flags' /proc/cpuinfo; } | sha256sum | cut -c1-16)" >> "$GITHUB_OUTPUT"

# load project cache to reduce compilation time, whose key additionally covers
# the Rust version, the Cargo.toml files, and build-relevant environment variables
- name: Setup project cache
uses: actions/cache@v3
continue-on-error: false
uses: Swatinem/rust-cache@v2
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: release-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
restore-keys: release-${{ runner.os }}-cargo-
key: ${{ steps.cpu.outputs.hash }}

- name: Set environment variables
run: |
Expand All @@ -46,18 +55,18 @@ jobs:
- name: Build
run: cargo build --release
- name: Generate docs
run: cargo doc
run: cargo doc --no-deps
- name: Run doc tests # Unit tests are run by tarpaulin
run: cargo test --doc --verbose

- name: Install cargo-tarpaulin
uses: baptiste0928/cargo-install@v2
uses: baptiste0928/cargo-install@v3
with:
crate: cargo-tarpaulin
- name: Calculate test coverage
run: cargo tarpaulin --out Html
- name: Archive code coverage results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.PROJECT_NAME }}-code_coverage_report-v${{ env.PROJECT_VERSION }}
path: tarpaulin-report.html
Expand All @@ -70,7 +79,7 @@ jobs:

# Cargo check for security issues
- name: Install cargo-audit
uses: baptiste0928/cargo-install@v2
uses: baptiste0928/cargo-install@v3
with:
crate: cargo-audit
- name: Security audit
Expand All @@ -81,9 +90,3 @@ jobs:
uses: dtolnay/install@cargo-outdated
- name: Outdated dependencies
run: cargo outdated --root-deps-only --exit-code 1

- name: Archive release build
uses: actions/upload-artifact@v4
with:
name: ${{ env.PROJECT_NAME }}-release_build-v${{ env.PROJECT_VERSION }}
path: target/release/${{ env.PROJECT_NAME }}
43 changes: 26 additions & 17 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ on:
branches:
- "**"

permissions:
contents: read

# a new run for the same branch or pull request cancels the outdated run
concurrency:
group: ${{ github.workflow_ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
RUSTDOCFLAGS: "-Dwarnings"
Expand All @@ -17,29 +25,30 @@ jobs:
pipeline:
name: Pipeline - code coverage + dependency check
runs-on: ubuntu-latest
timeout-minutes: 90

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7

- name: Setup dtolnay/rust-toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: clippy, rustfmt

# load project cache to reduce compilation time
# The native FLINT library is compiled for the CPU of the runner it is built on.
# Hence, the cache may only be reused on runners with the same CPU (model and features).
- name: Determine CPU of the runner
id: cpu
run: |
grep -m1 'model name' /proc/cpuinfo
echo "hash=$({ grep -m1 'model name' /proc/cpuinfo; grep -m1 '^flags' /proc/cpuinfo; } | sha256sum | cut -c1-16)" >> "$GITHUB_OUTPUT"

# load project cache to reduce compilation time, whose key additionally covers
# the Rust version, the Cargo.toml files, and build-relevant environment variables
- name: Setup project cache
uses: actions/cache@v3
continue-on-error: false
uses: Swatinem/rust-cache@v2
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-cargo-
key: ${{ steps.cpu.outputs.hash }}

- name: Set environment variables
run: |
Expand All @@ -51,18 +60,18 @@ jobs:
- name: Build
run: cargo build
- name: Generate docs
run: cargo doc
run: cargo doc --no-deps
- name: Run doc tests # Unit tests are run by tarpaulin
run: cargo test --doc --verbose

- name: Install cargo-tarpaulin
uses: baptiste0928/cargo-install@v2
uses: baptiste0928/cargo-install@v3
with:
crate: cargo-tarpaulin
- name: Calculate test coverage
run: cargo tarpaulin --out Html
- name: Archive code coverage results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.PROJECT_NAME }}-code_coverage_report-v${{ env.PROJECT_VERSION }}
path: tarpaulin-report.html
Expand All @@ -75,7 +84,7 @@ jobs:

# Cargo check for security issues
- name: Install cargo-audit
uses: baptiste0928/cargo-install@v2
uses: baptiste0928/cargo-install@v3
with:
crate: cargo-audit
- name: Security audit
Expand Down
37 changes: 23 additions & 14 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ on:
- main
- dev

permissions:
contents: read

# a new run for the same branch or pull request cancels the outdated run
concurrency:
group: ${{ github.workflow_ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
RUSTDOCFLAGS: "-Dwarnings"
Expand All @@ -15,36 +23,37 @@ jobs:
pipeline:
name: Pipeline - test and lints
runs-on: ubuntu-latest
timeout-minutes: 90

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7

- name: Setup dtolnay/rust-toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: clippy, rustfmt

# load project cache to reduce compilation time
# The native FLINT library is compiled for the CPU of the runner it is built on.
# Hence, the cache may only be reused on runners with the same CPU (model and features).
- name: Determine CPU of the runner
id: cpu
run: |
grep -m1 'model name' /proc/cpuinfo
echo "hash=$({ grep -m1 'model name' /proc/cpuinfo; grep -m1 '^flags' /proc/cpuinfo; } | sha256sum | cut -c1-16)" >> "$GITHUB_OUTPUT"

# load project cache to reduce compilation time, whose key additionally covers
# the Rust version, the Cargo.toml files, and build-relevant environment variables
- name: Setup project cache
uses: actions/cache@v3
continue-on-error: false
uses: Swatinem/rust-cache@v2
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-cargo-
key: ${{ steps.cpu.outputs.hash }}

- name: Update dependencies
run: cargo update
- name: Build
run: cargo build
- name: Generate docs
run: cargo doc
run: cargo doc --no-deps

- name: Test
run: cargo test --verbose
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "qfall-math"
version = "0.2.0"
version = "0.2.1"
edition = "2024"
rust-version = "1.86"
rust-version = "1.88"
description = "Mathematical foundations for rapid prototyping of lattice-based cryptography"
readme = "README.md"
homepage = "https://qfall.github.io"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This `math`-crate is a memory-safe wrapper of [FLINT](https://flintlib.org/) in

## Quick-Start
First, ensure that you use a Unix-like distribution (Linux or MacOS). Setup [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) if you're using Windows. This is required due to this crate's dependency on FLINT.
Then, make sure your `rustc --version` is `1.87` or newer.
Then, make sure your `rustc --version` is `1.88` or newer.

Furthermore, it's required that `m4`, a C-compiler such as `gcc`, and `make` are installed.
```bash
Expand Down
47 changes: 44 additions & 3 deletions src/integer_mod_q/mat_polynomial_ring_zq/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ impl MatPolynomialRingZq {
/// Creates a [`MatPolyOverZ`] where each entry is a representative of the
/// equivalence class of each entry from a [`MatPolynomialRingZq`] with coefficients centered around `0`.
///
/// The representation of the coefficients is in the range `[-modulus/2, modulus/2]` and
/// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
/// Each polynomial is reduced modulo the modulus polynomial and
/// each of its coefficients is in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`,
/// i.e. `[-(modulus-1)/2, (modulus-1)/2]` for odd moduli and `(-modulus/2, modulus/2]` for even moduli.
Comment thread
Marvin-Beckmann marked this conversation as resolved.
/// Hence, the positive representative is chosen for the element `modulus/2` of even moduli.
/// Use [`MatPolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be
/// in the range `[0, modulus)`.
///
Expand Down Expand Up @@ -76,7 +78,7 @@ impl MatPolynomialRingZq {
/// The representation of the coefficients is in the range `[0, modulus)` and
/// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
/// Use [`MatPolynomialRingZq::get_representative_least_absolute_residue`] if they should be
/// in the range `[-modulus/2, modulus/2]`.
/// in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`.
///
/// # Examples
/// ```
Expand Down Expand Up @@ -511,6 +513,45 @@ mod test_get_representative_least_absolute_residue {
let cmp_mat = MatPolyOverZ::from_str("[[3 10 0 -10]]").unwrap();
assert_eq!(cmp_mat, lar_mat);
}

/// Returns the coefficients `0, 1, ..., modulus - 1` and their representatives
/// according to `mod±` as defined in FIPS 204 as strings.
fn coefficients_and_representatives(modulus: i64) -> (String, String) {
let coefficients: Vec<String> = (0..modulus).map(|value| value.to_string()).collect();
let representatives: Vec<String> = (0..modulus)
.map(|value| {
if value > modulus / 2 {
value - modulus
} else {
value
}
.to_string()
})
.collect();
(coefficients.join(" "), representatives.join(" "))
}

/// Checks whether every coefficient is mapped into `(-⌈modulus/2⌉, ⌊modulus/2⌋]`
/// for an odd and an even modulus, i.e. `modulus/2` is mapped to the positive representative for even `modulus`.
#[test]
fn full_range() {
for modulus in [10, 11] {
let (coefficients, representatives) = coefficients_and_representatives(modulus);
// modulus polynomial `X^modulus + 1` s.t. no coefficient is reduced
let mat = MatPolynomialRingZq::from_str(&format!(
"[[{modulus} {coefficients}]] / {} 1 {}1 mod {modulus}",
modulus + 1,
"0 ".repeat(modulus as usize - 1)
))
.unwrap();

let lar_mat = mat.get_representative_least_absolute_residue();

let cmp_mat =
MatPolyOverZ::from_str(&format!("[[{modulus} {representatives}]]")).unwrap();
assert_eq!(cmp_mat, lar_mat);
}
}
}

#[cfg(test)]
Expand Down
27 changes: 24 additions & 3 deletions src/integer_mod_q/mat_zq/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl MatZq {
///
/// The values in the output matrix are in the range of `[0, modulus)`.
/// Use [`MatZq::get_representative_least_absolute_residue`] if they should be
/// in the range `[-modulus/2, modulus/2]`.
/// in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`.
///
/// Returns the matrix as a [`MatZ`].
///
Expand All @@ -52,8 +52,9 @@ impl MatZq {
/// equivalence class of each entry from a [`MatZq`] with the
/// representatives close to `0`.
///
/// The values in the output matrix are in the range of `[-modulus/2, modulus/2]`.
/// For even moduli, the positive representative is chosen for the element `modulus / 2`.
/// The values in the output matrix are in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`,
/// i.e. `[-(modulus-1)/2, (modulus-1)/2]` for odd moduli and `(-modulus/2, modulus/2]` for even moduli.
/// Hence, the positive representative is chosen for the element `modulus/2` of even moduli.
/// Use [`MatZq::get_representative_least_nonnegative_residue`] if they should be
/// in the range `[0, modulus)`.
///
Expand Down Expand Up @@ -964,4 +965,24 @@ mod test_get_representative_least_absolute_residue {
let mat_cmp = MatZ::from_str("[[0,1,2,3,4,5,-5,-4,-3,-2,-1,0]]").unwrap();
assert_eq!(mat_z.to_string(), mat_cmp.to_string());
}

/// Checks whether every entry is mapped to the same representative as by
/// [`Zq::get_representative_least_absolute_residue`] for an odd and an even modulus.
#[test]
fn consistent_with_zq() {
for modulus in [256, 257] {
let mut mat_zq = MatZq::new(1, modulus, modulus);
for value in 0..modulus {
mat_zq.set_entry(0, value, value).unwrap();
}

let mat_z = mat_zq.get_representative_least_absolute_residue();

for value in 0..modulus {
let entry: Z = mat_z.get_entry(0, value).unwrap();
let cmp = Zq::from((value, modulus)).get_representative_least_absolute_residue();
assert_eq!(cmp, entry);
}
}
}
}
Loading
Loading