qfall_math/integer_mod_q/z_q/
properties.rs

1// Copyright © 2023 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 includes functionality about properties of [`Zq`] instances.
10
11use super::Zq;
12use crate::traits::Pow;
13use flint_sys::{fmpz::fmpz_is_zero, fmpz_mod::fmpz_mod_is_one};
14
15impl Zq {
16    /// Returns the inverse of `self` as a fresh [`Zq`] instance.
17    /// It returns `None` if no inverse for `self mod q` exists.
18    ///
19    /// # Examples
20    /// ```
21    /// use qfall_math::integer_mod_q::Zq;
22    /// let value = Zq::from((4, 7));
23    ///
24    /// let inverse = value.inverse().unwrap();
25    ///
26    /// assert_eq!(Zq::from((2, 7)), inverse);
27    /// ```
28    pub fn inverse(&self) -> Option<Zq> {
29        self.pow(-1).ok()
30    }
31
32    /// Checks if a [`Zq`] is `0`.
33    ///
34    /// Returns `true` if the value is `0`.
35    ///
36    /// # Examples
37    /// ```
38    /// use qfall_math::integer_mod_q::Zq;
39    ///
40    /// let value = Zq::from((0, 7));
41    /// assert!(value.is_zero());
42    /// ```
43    pub fn is_zero(&self) -> bool {
44        1 == unsafe { fmpz_is_zero(&self.value.value) }
45    }
46
47    /// Checks if a [`Zq`] is `1`.
48    ///
49    /// Returns `true` if the value is `1`.
50    ///
51    /// # Examples
52    /// ```
53    /// use qfall_math::integer_mod_q::Zq;
54    ///
55    /// let value = Zq::from((1, 7));
56    /// assert!(value.is_one());
57    /// ```
58    pub fn is_one(&self) -> bool {
59        1 == unsafe { fmpz_mod_is_one(&self.value.value, self.modulus.get_fmpz_mod_ctx_struct()) }
60    }
61}
62
63#[cfg(test)]
64mod test_inv {
65    use super::Zq;
66
67    /// Checks whether the inverse is correctly computed for small values.
68    #[test]
69    fn small_values() {
70        let val_0 = Zq::from((4, 7));
71        let val_1 = Zq::from((-2, 7));
72
73        let inv_0 = val_0.inverse().unwrap();
74        let inv_1 = val_1.inverse().unwrap();
75
76        assert_eq!(Zq::from((2, 7)), inv_0);
77        assert_eq!(Zq::from((3, 7)), inv_1);
78    }
79
80    /// Checks whether the inverse is correctly computed for large values.
81    #[test]
82    fn large_values() {
83        let val_0 = Zq::from((i64::MAX, u64::MAX));
84        let val_1 = Zq::from((i64::MIN, u64::MAX));
85
86        let inv_0 = val_0.inverse().unwrap();
87        let inv_1 = val_1.inverse().unwrap();
88
89        assert_eq!(Zq::from((18446744073709551613_u64, u64::MAX)), inv_0);
90        assert_eq!(Zq::from((18446744073709551613_u64, u64::MAX)), inv_1);
91    }
92
93    /// Checks whether `inv` returns `None` for any values without an inverse.
94    #[test]
95    fn no_inverse_returns_none() {
96        let val_0 = Zq::from((4, 8));
97        let val_1 = Zq::from((3, 9));
98        let val_2 = Zq::from((0, 7));
99
100        assert!(val_0.inverse().is_none());
101        assert!(val_1.inverse().is_none());
102        assert!(val_2.inverse().is_none());
103    }
104}
105
106#[cfg(test)]
107mod test_is_zero {
108    use super::Zq;
109    use std::str::FromStr;
110
111    /// Ensure that is_zero returns `true` for `0`.
112    #[test]
113    fn zero_detection() {
114        let zero = Zq::from((0, 7));
115
116        assert!(zero.is_zero());
117    }
118
119    /// Ensure that is_zero returns `false` for non-zero values.
120    #[test]
121    fn zero_rejection() {
122        let small = Zq::from((4, 9));
123        let large =
124            Zq::from_str(&format!("{} mod {}", (u128::MAX - 1) / 2 + 1, u128::MAX)).unwrap();
125
126        assert!(!small.is_zero());
127        assert!(!large.is_zero());
128    }
129}
130
131#[cfg(test)]
132mod test_is_one {
133    use super::Zq;
134    use std::str::FromStr;
135
136    /// Ensure that is_one returns `true` for `1`.
137    #[test]
138    fn one_detection() {
139        let one = Zq::from((8, 7));
140
141        assert!(one.is_one());
142    }
143
144    /// Ensure that is_one returns `false` for other values.
145    #[test]
146    fn one_rejection() {
147        let small = Zq::from((12, 7));
148        let large =
149            Zq::from_str(&format!("{} mod {}", (u128::MAX - 1) / 2 + 2, u128::MAX)).unwrap();
150
151        assert!(!small.is_one());
152        assert!(!large.is_one());
153    }
154}