Skip to main content

qfall_math/integer_mod_q/z_q/
get.rs

1// Copyright 2023 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//! Get elements of [`Zq`] like its [`Z`] value and [`Modulus`].
10
11use crate::{
12    integer::Z,
13    integer_mod_q::{Modulus, Zq},
14};
15
16impl Zq {
17    /// Returns the [`Z`] value of the [`Zq`] element.
18    ///
19    /// The representation in the range `[0, modulus)` is returned.
20    /// Use [`Zq::get_representative_least_absolute_residue`] if they should be
21    /// in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`.
22    ///
23    /// # Examples
24    /// ```
25    /// use qfall_math::integer_mod_q::Zq;
26    /// use qfall_math::integer::Z;
27    /// let zq_value = Zq::from((4, 7));
28    ///
29    /// let z_value = zq_value.get_representative_least_nonnegative_residue();
30    ///
31    /// assert_eq!(Z::from(4), z_value);
32    /// ```
33    pub fn get_representative_least_nonnegative_residue(&self) -> Z {
34        self.value.clone()
35    }
36
37    /// Returns the [`Z`] value of the [`Zq`] element with the representatives close to `0`.
38    ///
39    /// The output value is in the range `(-⌈modulus/2⌉, ⌊modulus/2⌋]`,
40    /// i.e. `[-(modulus-1)/2, (modulus-1)/2]` for odd moduli and `(-modulus/2, modulus/2]` for even moduli.
41    /// Hence, the positive representative is chosen for the element `modulus/2` of even moduli.
42    /// Use [`Zq::get_representative_least_nonnegative_residue`] if they should be
43    /// in the range `[0, modulus)`.
44    ///
45    /// # Examples
46    /// ```
47    /// use qfall_math::integer_mod_q::Zq;
48    /// use qfall_math::integer::Z;
49    /// let zq_value = Zq::from((5, 7));
50    ///
51    /// let z_value = zq_value.get_representative_least_absolute_residue();
52    ///
53    /// assert_eq!(Z::from(-2), z_value);
54    /// ```
55    pub fn get_representative_least_absolute_residue(&self) -> Z {
56        let mod_z = Z::from(&self.modulus);
57        let mod_half = mod_z.div_floor(2);
58        if self.value > mod_half {
59            &self.value - mod_z
60        } else {
61            self.value.clone()
62        }
63    }
64
65    /// Returns the [`Modulus`] of the [`Zq`] element.
66    ///
67    /// # Examples
68    /// ```
69    /// use qfall_math::integer_mod_q::{Zq, Modulus};
70    /// use std::str::FromStr;
71    /// let value = Zq::from((4, 7));
72    /// let cmp = Modulus::from(7);
73    ///
74    /// let modulus = value.get_mod();
75    ///
76    /// assert_eq!(cmp, modulus);
77    /// ```
78    pub fn get_mod(&self) -> Modulus {
79        self.modulus.clone()
80    }
81}
82
83#[cfg(test)]
84mod test_get_representative_least_nonnegative_residue {
85    use super::{Z, Zq};
86
87    /// Check whether `get_representative_least_nonnegative_residue` outputs the correct value for small values
88    #[test]
89    fn get_small() {
90        let value_0 = Zq::from((2, 20));
91        let value_1 = Zq::from((-2, 20));
92
93        let res_0 = value_0.get_representative_least_nonnegative_residue();
94        let res_1 = value_1.get_representative_least_nonnegative_residue();
95
96        assert_eq!(res_0, Z::from(2));
97        assert_eq!(res_1, Z::from(18));
98    }
99
100    /// Check whether `get_representative_least_nonnegative_residue` outputs the correct value for large values
101    #[test]
102    fn get_large() {
103        let value_0 = Zq::from((i64::MAX, u64::MAX));
104        let value_1 = Zq::from((i64::MIN, u64::MAX));
105
106        let res_0 = value_0.get_representative_least_nonnegative_residue();
107        let res_1 = value_1.get_representative_least_nonnegative_residue();
108
109        assert_eq!(res_0, Z::from(i64::MAX));
110        assert_eq!(res_1, Z::from(i64::MAX));
111    }
112}
113
114#[cfg(test)]
115mod test_get_representative_least_absolute_residue {
116    use super::{Z, Zq};
117
118    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for small values
119    #[test]
120    fn get_small() {
121        let value_0 = Zq::from((2, 20));
122        let value_1 = Zq::from((-2, 20));
123
124        let res_0 = value_0.get_representative_least_absolute_residue();
125        let res_1 = value_1.get_representative_least_absolute_residue();
126
127        assert_eq!(res_0, Z::from(2));
128        assert_eq!(res_1, Z::from(-2));
129    }
130
131    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values
132    #[test]
133    fn get_large() {
134        let value_0 = Zq::from((i64::MAX, u64::MAX));
135        let value_1 = Zq::from((u64::MAX - 1, u64::MAX));
136
137        let res_0 = value_0.get_representative_least_absolute_residue();
138        let res_1 = value_1.get_representative_least_absolute_residue();
139
140        assert_eq!(res_0, Z::from(i64::MAX));
141        assert_eq!(res_1, Z::from(-1));
142    }
143
144    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases
145    #[test]
146    fn get_special() {
147        let value_0 = Zq::from((10, 20));
148        let value_1 = Zq::from((0, 20));
149        let value_2 = Zq::from((11, 21));
150
151        let res_0 = value_0.get_representative_least_absolute_residue();
152        let res_1 = value_1.get_representative_least_absolute_residue();
153        let res_2 = value_2.get_representative_least_absolute_residue();
154
155        assert_eq!(res_0, Z::from(10));
156        assert_eq!(res_1, Z::from(0));
157        assert_eq!(res_2, Z::from(-10));
158    }
159
160    /// Checks whether an element of the upper half is mapped to its negative representative,
161    /// i.e. `256 mod 257` to `-1`.
162    #[test]
163    fn upper_half_negative() {
164        let value = Zq::from((256, 257));
165
166        let res = value.get_representative_least_absolute_residue();
167
168        assert_eq!(Z::MINUS_ONE, res);
169    }
170
171    /// Checks whether every element is mapped into `(-⌈modulus/2⌉, ⌊modulus/2⌋]`
172    /// according to `mod±` as defined in FIPS 204 for an odd and an even modulus.
173    #[test]
174    fn full_range() {
175        for modulus in [256, 257] {
176            for value in 0..modulus {
177                let expected = if value > modulus / 2 {
178                    value - modulus
179                } else {
180                    value
181                };
182
183                let res = Zq::from((value, modulus)).get_representative_least_absolute_residue();
184
185                assert_eq!(Z::from(expected), res);
186            }
187        }
188    }
189}
190
191#[cfg(test)]
192mod test_get_mod {
193    use super::{Modulus, Zq};
194
195    /// Check whether `get_mod` outputs the correct modulus for small moduli
196    #[test]
197    fn get_small() {
198        let value = Zq::from((2, 20));
199
200        let modulus = value.get_mod();
201
202        assert_eq!(modulus, Modulus::from(20));
203    }
204
205    /// Check whether `get_mod` outputs the correct modulus for large moduli
206    #[test]
207    fn get_large() {
208        let value = Zq::from((2, u64::MAX));
209
210        let modulus = value.get_mod();
211
212        assert_eq!(modulus, Modulus::from(u64::MAX));
213    }
214}