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}