qfall_math/integer_mod_q/z_q/
from.rs

1// Copyright © 2023 Sven Moog, Marcel Luca Schmidt, 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//! Implementations to create a [`Zq`] value from other types.
10//!
11//! The explicit functions contain the documentation.
12
13use super::Zq;
14use crate::{
15    error::{MathError, StringConversionError},
16    integer::Z,
17    integer_mod_q::Modulus,
18};
19use std::str::FromStr;
20
21impl<Mod: Into<Modulus>> From<Mod> for Zq {
22    /// Creates a zero integer with a given [`Modulus`].
23    ///
24    /// Parameters:
25    /// - `modulus`: of the new [`Zq`]
26    ///
27    /// Returns a new constant [`Zq`] with the specified [`Modulus`].
28    ///
29    /// # Examples
30    /// ```
31    /// use qfall_math::integer_mod_q::Zq;
32    /// use std::str::FromStr;
33    ///
34    /// let zq = Zq::from(100);
35    ///
36    /// let zq_cmp = Zq::from_str("0 mod 100").unwrap();
37    /// assert_eq!(zq, zq_cmp);
38    /// ```
39    ///
40    /// # Panics ...
41    /// - if `modulus` is smaller than `2`.
42    fn from(modulus: Mod) -> Self {
43        let value = Z::default();
44        let modulus = modulus.into();
45
46        let mut out = Zq { value, modulus };
47        out.reduce();
48        out
49    }
50}
51
52impl<IntegerValue: Into<Z>, IntegerModulus: Into<Modulus>> From<(IntegerValue, IntegerModulus)>
53    for Zq
54{
55    /// Creates a [`Zq`] from a tuple with the integer and the modulus.
56    ///
57    /// Parameters:
58    /// - `value`: Defines the value of the residue class.
59    /// - `modulus`: Defines the modulus by which `value` is reduced.
60    ///
61    /// Note that the strings for integer and modulus are trimmed,
62    /// i.e. all whitespaces around all values are ignored.
63    ///
64    /// Returns the `value` mod `modulus` as a [`Zq`].
65    ///
66    /// # Examples
67    /// ```
68    /// use qfall_math::integer_mod_q::Zq;
69    /// use qfall_math::integer::Z;
70    ///
71    /// let answer_1 = Zq::from((1337 + 42, 1337));
72    /// let answer_2 = Zq::from((Z::from(42), 1337));
73    ///
74    /// assert_eq!(answer_1, answer_2);
75    /// ```
76    ///
77    /// # Panics ...
78    /// - if `modulus` is smaller than `2`.
79    fn from((value, modulus): (IntegerValue, IntegerModulus)) -> Self {
80        let value = value.into();
81        let modulus = modulus.into();
82
83        let mut out = Zq { value, modulus };
84        out.reduce();
85        out
86    }
87}
88
89impl FromStr for Zq {
90    type Err = MathError;
91
92    /// Creates a [`Zq`] integer from a [`String`].
93    ///
94    /// Parameters:
95    /// - `s`: the integer and modulus value of form: `"12 mod 25"` for the number 12
96    ///   under the modulus 25.
97    ///
98    /// Returns a [`Zq`] or an error if the provided string was not formatted
99    /// correctly.
100    ///
101    /// # Examples
102    /// ```
103    /// use std::str::FromStr;
104    /// use qfall_math::integer_mod_q::Zq;
105    ///  
106    /// let a: Zq = "100 mod 3".parse().unwrap();
107    /// let b: Zq = Zq::from_str("100 mod 3").unwrap();
108    /// ```
109    ///
110    /// # Errors and Failures
111    /// - Returns a [`MathError`] of type
112    ///   [`StringConversionError`](MathError::StringConversionError)
113    ///     - if the provided string contains a `Null` byte,
114    ///     - if the provided string was not formatted correctly,
115    ///     - if the provided modulus was not formatted correctly to create a [`Z`], or
116    ///     - if the delimiter `mod` could not be found.
117    /// - Returns a [`MathError`] of type
118    ///   [`InvalidModulus`](MathError::InvalidModulus)
119    ///   if the provided value is smaller than `2`.
120    /// - Returns a [`MathError`] of type
121    fn from_str(s: &str) -> Result<Self, Self::Err> {
122        let input_split: Vec<&str> = s.split("mod").collect();
123        if input_split.len() != 2 {
124            return Err(StringConversionError::InvalidStringToZqInput(s.to_owned()))?;
125        }
126
127        // instantiate both parts of Zq element
128        let modulus = Modulus::from_str(input_split[1].trim())?;
129        let value = Z::from_str(input_split[0].trim())?;
130
131        let mut out = Self { value, modulus };
132        out.reduce();
133
134        Ok(out)
135    }
136}
137
138impl From<&Zq> for Zq {
139    /// An alias for [`Zq::clone`].
140    /// It makes the use of generic `Into<Zq>` types easier.
141    fn from(value: &Zq) -> Self {
142        value.clone()
143    }
144}
145
146impl Zq {
147    /// Create a [`Zq`] integer from a [`String`], i.e. its UTF8-Encoding.
148    /// The inverse of this function is [`Zq::to_utf8`].
149    ///
150    /// Parameters:
151    /// - `message`: specifies the message that is transformed via its UTF8-Encoding
152    ///   to a new [`Zq`] instance.
153    /// - `modulus`: Defines the modulus by which `value` is reduced.
154    ///
155    /// Returns value defined by `message` mod `modulus` as [`Zq`] or a [`MathError`]
156    /// if the provided modulus is smaller than the UTF8-Encoding of the message.
157    ///
158    /// # Examples
159    /// ```
160    /// use qfall_math::integer_mod_q::Zq;
161    /// let message = "hello!";
162    ///  
163    /// let value = Zq::from_utf8(&message, i64::MAX).unwrap();
164    /// assert_eq!(Zq::from((36762444129640u64, i64::MAX)), value);
165    /// ```
166    ///
167    /// # Errors and Failures
168    /// - Returns a [`ConversionError`](MathError::ConversionError) if the provided modulus
169    ///   is smaller than the UTF8-Encoding of the message.
170    ///
171    /// # Panics ...
172    /// - if `modulus` is smaller than `2`.
173    pub fn from_utf8(message: &str, modulus: impl Into<Modulus>) -> Result<Zq, MathError> {
174        let modulus: Modulus = modulus.into();
175        let modulus_as_z: Z = (&modulus).into();
176        let value = Z::from_utf8(message);
177
178        if modulus_as_z > value {
179            return Ok(Zq::from((value, &modulus)));
180        }
181        Err(MathError::ConversionError(
182            "The provided modulus is smaller than the UTF8-Encoding of your message.".to_owned(),
183        ))
184    }
185}
186
187#[cfg(test)]
188mod test_from_mod {
189    use crate::integer_mod_q::Zq;
190    use std::str::FromStr;
191
192    /// Ensure that the resulting value is zero and the modulus is correctly instantiated.
193    #[test]
194    fn modulus_zero() {
195        let zq = Zq::from(100);
196
197        assert_eq!(zq, Zq::from_str("0 mod 100").unwrap());
198    }
199
200    /// Ensure that initializing large moduli works.
201    #[test]
202    fn modulus_large() {
203        let zq = Zq::from(u64::MAX);
204
205        assert_eq!(zq, Zq::from_str(&format!("0 mod {}", u64::MAX)).unwrap());
206    }
207
208    /// Ensure that mod 0 results in a panic.
209    #[test]
210    #[should_panic]
211    fn modulus_0() {
212        let _ = Zq::from(0);
213    }
214
215    /// Ensure that mod 1 results in a panic.
216    #[test]
217    #[should_panic]
218    fn modulus_1() {
219        let _ = Zq::from(1);
220    }
221
222    /// Ensure that a negative modulus results in a panic.
223    #[test]
224    #[should_panic]
225    fn modulus_negative() {
226        let _ = Zq::from(-1);
227    }
228}
229
230#[cfg(test)]
231mod test_from_trait {
232    use crate::{
233        integer::Z,
234        integer_mod_q::{Modulus, Zq},
235    };
236
237    /// Test that the different combinations of rust integers, [`Z`], and [`Modulus`]
238    /// in their owned and borrowed form can be used to create a [`Zq`].
239    #[test]
240    fn different_types() {
241        let int_8: i8 = 10;
242        let int_16: i16 = 10;
243        let int_32: i32 = 10;
244        let int_64: i64 = 10;
245        let uint_8: u8 = 10;
246        let uint_16: u16 = 10;
247        let uint_32: u32 = 10;
248        let uint_64: u64 = 10;
249        let z = Z::from(10);
250        let modulus = Modulus::from(10);
251
252        // owned, owned the same type in numerator and denominator
253        let _ = Zq::from((int_8, int_8));
254        let _ = Zq::from((int_16, int_16));
255        let _ = Zq::from((int_32, int_32));
256        let _ = Zq::from((int_64, int_64));
257        let _ = Zq::from((uint_8, uint_8));
258        let _ = Zq::from((uint_16, uint_16));
259        let _ = Zq::from((uint_32, uint_32));
260        let _ = Zq::from((uint_64, uint_64));
261        let _ = Zq::from((z.clone(), z.clone()));
262        let _ = Zq::from((modulus.clone(), modulus.clone()));
263
264        // borrowed, borrowed the same type in numerator and denominator
265        let _ = Zq::from((&int_8, &int_8));
266        let _ = Zq::from((&int_16, &int_16));
267        let _ = Zq::from((&int_32, &int_32));
268        let _ = Zq::from((&int_64, &int_64));
269        let _ = Zq::from((&uint_8, &uint_8));
270        let _ = Zq::from((&uint_16, &uint_16));
271        let _ = Zq::from((&uint_32, &uint_32));
272        let _ = Zq::from((&uint_64, &uint_64));
273        let _ = Zq::from((&z, &z));
274        let _ = Zq::from((&modulus, &modulus));
275
276        // From now on assume that i/u8, i/u16, i/u32 and i/u64 behave the same.
277        // This assumption is reasonable, since their implementation is the same.
278
279        // owned, owned mixed types
280        let _ = Zq::from((int_8, z.clone()));
281        let _ = Zq::from((z.clone(), int_8));
282        let _ = Zq::from((int_8, modulus.clone()));
283        let _ = Zq::from((z.clone(), modulus.clone()));
284        let _ = Zq::from((modulus.clone(), int_8));
285        let _ = Zq::from((modulus.clone(), z.clone()));
286
287        // owned, borrowed mixed types
288        let _ = Zq::from((int_8, &z));
289        let _ = Zq::from((modulus.clone(), &z));
290        let _ = Zq::from((z.clone(), &int_8));
291        let _ = Zq::from((z.clone(), &modulus));
292        let _ = Zq::from((int_8, &modulus));
293        let _ = Zq::from((modulus.clone(), &int_8));
294
295        // borrowed, owned mixed types
296        let _ = Zq::from((&int_8, z.clone()));
297        let _ = Zq::from((&modulus, z.clone()));
298        let _ = Zq::from((&z, int_8));
299        let _ = Zq::from((&z, modulus.clone()));
300        let _ = Zq::from((&int_8, modulus.clone()));
301        let _ = Zq::from((&modulus, int_8));
302
303        // borrowed, borrowed mixed types
304        let _ = Zq::from((&int_8, &z));
305        let _ = Zq::from((&modulus, &z));
306        let _ = Zq::from((&z, &int_8));
307        let _ = Zq::from((&z, &modulus));
308        let _ = Zq::from((&int_8, &modulus));
309        let _ = Zq::from((&modulus, &int_8));
310    }
311
312    /// Ensure that the modulus calculation is performed at initialization.
313    #[test]
314    fn modulus_at_initialization() {
315        let a = Zq::from((0, 10));
316        let b = Zq::from((10, 10));
317
318        assert_eq!(a, b);
319    }
320
321    /// Test with small valid value and modulus.
322    #[test]
323    fn working_small() {
324        let zq_1 = Zq::from((10, 15));
325        let zq_2 = Zq::from((Z::from(10), Modulus::from(15)));
326
327        assert_eq!(zq_1, zq_2);
328    }
329
330    /// Test with large value and modulus (FLINT uses pointer representation).
331    #[test]
332    fn working_large() {
333        let zq_1 = Zq::from((u64::MAX - 1, u64::MAX));
334        let zq_2 = Zq::from((&Z::from(u64::MAX - 1), Modulus::from(u64::MAX)));
335
336        assert_eq!(zq_1, zq_2);
337    }
338
339    /// Test with `0` modulus (not valid)
340    #[test]
341    #[should_panic]
342    fn modulus_zero() {
343        let _ = Zq::from((10, 0));
344    }
345
346    /// Test with negative modulus (not valid)
347    #[test]
348    #[should_panic]
349    fn modulus_negative() {
350        let _ = Zq::from((10, -1));
351    }
352}
353
354#[cfg(test)]
355mod tests_from_str {
356    use crate::integer_mod_q::Zq;
357    use std::str::FromStr;
358
359    /// Ensure that initialization with large numbers works.
360    #[test]
361    fn max_int_positive() {
362        assert!(Zq::from_str(&format!("{} mod {}", i64::MAX, u64::MAX)).is_ok());
363    }
364
365    /// Ensure that initialization with large numbers (larger than [`i64`]) works.
366    #[test]
367    fn large_positive() {
368        assert!(Zq::from_str(&format!("{} mod {}", u64::MAX, u128::MAX)).is_ok());
369    }
370
371    /// Ensure that initialization with large negative numbers works.
372    #[test]
373    fn max_int_negative() {
374        assert!(Zq::from_str(&format!("-{} mod {}", i64::MAX, u64::MAX)).is_ok());
375    }
376
377    /// Ensure that initialization with large negative numbers (larger than [`i64`]) works.
378    #[test]
379    fn large_negative() {
380        assert!(Zq::from_str(&format!("-{} mod {}", u64::MAX, u128::MAX)).is_ok());
381    }
382
383    /// Ensure that initialization with standard values works.
384    #[test]
385    fn normal_value() {
386        assert!(Zq::from_str("42 mod 5").is_ok());
387    }
388
389    /// Ensure that initialization works with leading and trailing whitespaces.
390    #[test]
391    fn whitespaces_work() {
392        assert!(Zq::from_str("    42 mod 5").is_ok());
393        assert!(Zq::from_str("42 mod 5    ").is_ok());
394        assert!(Zq::from_str("42    mod 5").is_ok());
395        assert!(Zq::from_str("42 mod     5").is_ok());
396    }
397
398    /// Ensure that initialization yields an error with whitespaces in between.
399    #[test]
400    fn whitespaces_error() {
401        assert!(Zq::from_str("4 2 mod 5").is_err());
402        assert!(Zq::from_str("42 mo d 5").is_err());
403        assert!(Zq::from_str("42 mod 5 0").is_err());
404    }
405
406    /// Ensure that wrong initialization yields an Error.
407    #[test]
408    fn error_wrong_letters() {
409        assert!(Zq::from_str("hbrkt35itu3gg").is_err());
410        assert!(Zq::from_str("3-2 mod 3").is_err());
411        assert!(Zq::from_str("3 5").is_err());
412        assert!(Zq::from_str("3%5").is_err());
413        assert!(Zq::from_str("3/5 mod 3").is_err());
414    }
415}
416
417#[cfg(test)]
418/// Test the implementation of [`Zq::from_utf8`] briefly.
419/// This module omits tests that were already provided for [`crate::integer::Z::from_utf8`].
420mod test_from_utf8 {
421    use super::Zq;
422
423    /// Ensures that values that are larger than the modulus result in an error.
424    #[test]
425    fn not_enough_memory() {
426        let message = "some_long message with too many bytes";
427        let modulus = u32::MAX;
428
429        let value = Zq::from_utf8(message, modulus);
430
431        assert!(value.is_err());
432    }
433
434    /// Ensures that using a modulus smaller than `2` results in a panic.
435    #[test]
436    #[should_panic]
437    fn modulus_too_small() {
438        let message = "something";
439        let modulus = 1;
440
441        let _ = Zq::from_utf8(message, modulus);
442    }
443}