Skip to main content

qfall_math/integer_mod_q/modulus/
unsafe_functions.rs

1// Copyright 2025 Jan 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::Modulus;
13use crate::macros::unsafe_passthrough::unsafe_getter_mod;
14use flint3_sys::{fmpz_mod_ctx, fmpz_mod_ctx_clear};
15
16unsafe_getter_mod!(Modulus, modulus, fmpz_mod_ctx);
17
18impl Modulus {
19    /// Sets a mutable reference to the field `modulus` of type [`Modulus`] to a given `fmpz_mod_ctx`.
20    ///
21    /// Parameters:
22    /// - `flint_struct`: value to set the attribute to
23    ///
24    /// **WARNING:** The set struct is part of [`flint3_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 [`flint3_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 [`flint3_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 [`flint3_sys`] can introduce memory leaks.
44    pub unsafe fn set_fmpz_mod_ctx(&mut self, flint_struct: fmpz_mod_ctx) {
45        let ptr = std::rc::Rc::as_ptr(&self.modulus) as *mut _;
46        let modulus = unsafe { &mut *ptr };
47
48        // free memory of old modulus before new values of modulus are copied
49        unsafe { fmpz_mod_ctx_clear(modulus) };
50
51        modulus.add_fxn = flint_struct.add_fxn;
52        modulus.mod_ = flint_struct.mod_;
53        modulus.mul_fxn = flint_struct.mul_fxn;
54        modulus.n = flint_struct.n;
55        modulus.n_limbs = flint_struct.n_limbs;
56        modulus.ninv_limbs = flint_struct.ninv_limbs;
57        modulus.sub_fxn = flint_struct.sub_fxn;
58    }
59}
60
61#[cfg(test)]
62mod test_get_fmpz_mod_ctx {
63    use super::Modulus;
64
65    /// Checks availability of the getter for [`Modulus::modulus`]
66    /// and its ability to be modified.
67    #[test]
68    #[allow(unused_mut)]
69    fn availability_and_modification() {
70        let mut modulus = Modulus::from(3);
71
72        let mut fmpz_mod = unsafe { modulus.get_fmpz_mod_ctx() };
73
74        fmpz_mod.n[0] = 2;
75
76        assert_eq!(Modulus::from(2), modulus);
77    }
78}
79
80#[cfg(test)]
81mod test_set_fmpz_mod_ctx {
82    use super::Modulus;
83    use flint3_sys::fmpz_mod_ctx_init;
84    use std::mem::MaybeUninit;
85
86    /// Checks availability of the setter for [`Modulus::modulus`]
87    /// and its ability to modify [`Modulus`].
88    #[test]
89    #[allow(unused_mut)]
90    fn availability_and_modification() {
91        let mut modulus = Modulus::from(3);
92
93        let mut flint_struct = MaybeUninit::uninit();
94        let mut flint_struct = unsafe {
95            fmpz_mod_ctx_init(flint_struct.as_mut_ptr(), &2);
96            flint_struct.assume_init()
97        };
98
99        unsafe { modulus.set_fmpz_mod_ctx(flint_struct) };
100
101        assert_eq!(Modulus::from(2), modulus);
102    }
103}