qfall_math/integer_mod_q/modulus_polynomial_ring_zq/
unsafe_functions.rs

1// Copyright © 2025 Niklas Siemer
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module contains public functions that enable access to underlying
10//! [FLINT](https://flintlib.org/) structs. Therefore, they require to be unsafe.
11
12use super::ModulusPolynomialRingZq;
13use crate::macros::unsafe_passthrough::unsafe_getter_mod;
14use flint_sys::fq::{fq_ctx_clear, fq_ctx_struct};
15
16unsafe_getter_mod!(ModulusPolynomialRingZq, modulus, fq_ctx_struct);
17
18impl ModulusPolynomialRingZq {
19    /// Sets a mutable reference to the field `modulus` of type [`ModulusPolynomialRingZq`] to a given `fq_ctx_struct`.
20    ///
21    /// Parameters:
22    /// - `flint_struct`: value to set the attribute to
23    ///
24    /// **WARNING:** The returned struct is part of [`flint_sys`].
25    /// Any changes to this object are unsafe and may introduce memory leaks.
26    /// Please be aware that most moduli are shared across multiple instances and all
27    /// modifications of this struct will affect any other instance with a reference to this object.
28    ///
29    /// This function is a passthrough to enable users of this library to use [`flint_sys`]
30    /// and with that [FLINT](https://flintlib.org/) functions that might not be covered in our library yet.
31    /// If this is the case, please consider contributing to this open-source project
32    /// by opening a Pull Request at [qfall_math](https://github.com/qfall/math)
33    /// to provide this feature in the future.
34    ///
35    /// # Safety
36    /// Ensure that the old `modulus` does not share any memory with any moduli
37    /// that might be used in the future. The memory of the old `modulus` is freed
38    /// using this function.
39    ///
40    /// Any [`flint_sys`] struct and function is part of a FFI to the C-library `FLINT`.
41    /// As `FLINT` is a C-library, it does not provide all memory safety features
42    /// that Rust and our Wrapper provide.
43    /// Thus, using functions of [`flint_sys`] can introduce memory leaks.
44    pub unsafe fn set_fq_ctx_struct(&mut self, flint_struct: fq_ctx_struct) {
45        let modulus = std::rc::Rc::<fq_ctx_struct>::get_mut(&mut self.modulus).unwrap();
46
47        // free memory of old modulus before new values of modulus are copied
48        unsafe { fq_ctx_clear(modulus) };
49
50        modulus.a = flint_struct.a;
51        modulus.ctxp = flint_struct.ctxp;
52        modulus.inv = flint_struct.inv;
53        modulus.is_conway = flint_struct.is_conway;
54        modulus.j = flint_struct.j;
55        modulus.len = flint_struct.len;
56        modulus.modulus = flint_struct.modulus;
57        modulus.sparse_modulus = flint_struct.sparse_modulus;
58        modulus.var = flint_struct.var;
59    }
60}
61
62#[cfg(test)]
63mod test_get_fq_ctx_struct {
64    use super::ModulusPolynomialRingZq;
65    use std::str::FromStr;
66
67    /// Checks availability of the getter for [`ModulusPolynomialRingZq::modulus`]
68    /// and its ability to be modified.
69    #[test]
70    #[allow(unused_mut)]
71    fn availability_and_modification() {
72        let mut modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 7").unwrap();
73        let cmp_mod = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 5").unwrap();
74
75        let mut fmpz_mod = unsafe { modulus.get_fq_ctx_struct() };
76
77        fmpz_mod.ctxp[0].n[0].0 = 5;
78
79        assert_eq!(cmp_mod, modulus);
80    }
81}
82
83#[cfg(test)]
84mod test_set_fq_ctx_struct {
85    use super::ModulusPolynomialRingZq;
86    use crate::{integer::Z, integer_mod_q::PolyOverZq, traits::GetCoefficient};
87    use flint_sys::{
88        fmpz::fmpz,
89        fmpz_mod::fmpz_mod_ctx_init,
90        fmpz_mod_poly::{fmpz_mod_poly_init, fmpz_mod_poly_set_coeff_fmpz},
91        fq::fq_ctx_init_modulus,
92    };
93    use std::{ffi::CString, mem::MaybeUninit, str::FromStr};
94
95    /// Checks availability of the setter for [`ModulusPolynomialRingZq::modulus`]
96    /// and its ability to modify [`ModulusPolynomialRingZq`].
97    #[test]
98    #[allow(unused_mut)]
99    fn availability_and_modification() {
100        let poly_zq = PolyOverZq::from_str("2  2 3 mod 7").unwrap();
101        let mut test_struct = ModulusPolynomialRingZq::from(poly_zq);
102        // Setup modulus, i.e. mod 11
103        let mut modulus = MaybeUninit::uninit();
104        let mut modulus = unsafe {
105            fmpz_mod_ctx_init(modulus.as_mut_ptr(), &fmpz(11));
106            modulus.assume_init()
107        };
108        // Setup ModulusPolynomial, i.e. 7 mod 11
109        let mut poly = MaybeUninit::uninit();
110        let mut poly = unsafe {
111            fmpz_mod_poly_init(poly.as_mut_ptr(), &modulus);
112            poly.assume_init()
113        };
114        unsafe {
115            fmpz_mod_poly_set_coeff_fmpz(&mut poly, 1, &fmpz(7), &modulus);
116        };
117        // Setup ModPolynomialRingZq
118        let mut mod_poly_ring_zq = MaybeUninit::uninit();
119        let c_string = CString::new("X").unwrap();
120        let mod_poly_ring_zq = unsafe {
121            fq_ctx_init_modulus(
122                mod_poly_ring_zq.as_mut_ptr(),
123                &poly,
124                &modulus,
125                c_string.as_ptr(),
126            );
127            mod_poly_ring_zq.assume_init()
128        };
129
130        unsafe { test_struct.set_fq_ctx_struct(mod_poly_ring_zq) };
131
132        assert_eq!(Z::from(11), test_struct.get_q());
133        assert_eq!(1, test_struct.get_degree());
134        assert_eq!(
135            Z::from(7),
136            GetCoefficient::<Z>::get_coeff(&test_struct, 1).unwrap()
137        );
138    }
139}