use super::Zq;
use crate::{
error::{MathError, StringConversionError},
integer::Z,
integer_mod_q::Modulus,
};
use std::str::FromStr;
impl<Mod: Into<Modulus>> From<Mod> for Zq {
fn from(modulus: Mod) -> Self {
let value = Z::default();
let modulus = modulus.into();
let mut out = Zq { value, modulus };
out.reduce();
out
}
}
impl<IntegerValue: Into<Z>, IntegerModulus: Into<Modulus>> From<(IntegerValue, IntegerModulus)>
for Zq
{
fn from((value, modulus): (IntegerValue, IntegerModulus)) -> Self {
let value = value.into();
let modulus = modulus.into();
let mut out = Zq { value, modulus };
out.reduce();
out
}
}
impl FromStr for Zq {
type Err = MathError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let input_split: Vec<&str> = s.split("mod").collect();
if input_split.len() != 2 {
return Err(StringConversionError::InvalidStringToZqInput(s.to_owned()))?;
}
let modulus = Modulus::from_str(input_split[1].trim())?;
let value = Z::from_str(input_split[0].trim())?;
let mut out = Self { value, modulus };
out.reduce();
Ok(out)
}
}
impl From<&Zq> for Zq {
fn from(value: &Zq) -> Self {
value.clone()
}
}
impl Zq {
pub fn from_utf8(message: &str, modulus: impl Into<Modulus>) -> Result<Zq, MathError> {
let modulus: Modulus = modulus.into();
let modulus_as_z: Z = (&modulus).into();
let value = Z::from_utf8(message);
if modulus_as_z > value {
return Ok(Zq::from((value, &modulus)));
}
Err(MathError::ConversionError(
"The provided modulus is smaller than the UTF8-Encoding of your message.".to_owned(),
))
}
}
#[cfg(test)]
mod test_from_mod {
use crate::integer_mod_q::Zq;
use std::str::FromStr;
#[test]
fn modulus_zero() {
let zq = Zq::from(100);
assert_eq!(zq, Zq::from_str("0 mod 100").unwrap());
}
#[test]
fn modulus_large() {
let zq = Zq::from(u64::MAX);
assert_eq!(zq, Zq::from_str(&format!("0 mod {}", u64::MAX)).unwrap());
}
#[test]
#[should_panic]
fn modulus_0() {
let _ = Zq::from(0);
}
#[test]
#[should_panic]
fn modulus_1() {
let _ = Zq::from(1);
}
#[test]
#[should_panic]
fn modulus_negative() {
let _ = Zq::from(-1);
}
}
#[cfg(test)]
mod test_from_trait {
use crate::{
integer::Z,
integer_mod_q::{Modulus, Zq},
};
#[test]
fn different_types() {
let int_8: i8 = 10;
let int_16: i16 = 10;
let int_32: i32 = 10;
let int_64: i64 = 10;
let uint_8: u8 = 10;
let uint_16: u16 = 10;
let uint_32: u32 = 10;
let uint_64: u64 = 10;
let z = Z::from(10);
let modulus = Modulus::from(10);
let _ = Zq::from((int_8, int_8));
let _ = Zq::from((int_16, int_16));
let _ = Zq::from((int_32, int_32));
let _ = Zq::from((int_64, int_64));
let _ = Zq::from((uint_8, uint_8));
let _ = Zq::from((uint_16, uint_16));
let _ = Zq::from((uint_32, uint_32));
let _ = Zq::from((uint_64, uint_64));
let _ = Zq::from((z.clone(), z.clone()));
let _ = Zq::from((modulus.clone(), modulus.clone()));
let _ = Zq::from((&int_8, &int_8));
let _ = Zq::from((&int_16, &int_16));
let _ = Zq::from((&int_32, &int_32));
let _ = Zq::from((&int_64, &int_64));
let _ = Zq::from((&uint_8, &uint_8));
let _ = Zq::from((&uint_16, &uint_16));
let _ = Zq::from((&uint_32, &uint_32));
let _ = Zq::from((&uint_64, &uint_64));
let _ = Zq::from((&z, &z));
let _ = Zq::from((&modulus, &modulus));
let _ = Zq::from((int_8, z.clone()));
let _ = Zq::from((z.clone(), int_8));
let _ = Zq::from((int_8, modulus.clone()));
let _ = Zq::from((z.clone(), modulus.clone()));
let _ = Zq::from((modulus.clone(), int_8));
let _ = Zq::from((modulus.clone(), z.clone()));
let _ = Zq::from((int_8, &z));
let _ = Zq::from((modulus.clone(), &z));
let _ = Zq::from((z.clone(), &int_8));
let _ = Zq::from((z.clone(), &modulus));
let _ = Zq::from((int_8, &modulus));
let _ = Zq::from((modulus.clone(), &int_8));
let _ = Zq::from((&int_8, z.clone()));
let _ = Zq::from((&modulus, z.clone()));
let _ = Zq::from((&z, int_8));
let _ = Zq::from((&z, modulus.clone()));
let _ = Zq::from((&int_8, modulus.clone()));
let _ = Zq::from((&modulus, int_8));
let _ = Zq::from((&int_8, &z));
let _ = Zq::from((&modulus, &z));
let _ = Zq::from((&z, &int_8));
let _ = Zq::from((&z, &modulus));
let _ = Zq::from((&int_8, &modulus));
let _ = Zq::from((&modulus, &int_8));
}
#[test]
fn modulus_at_initialization() {
let a = Zq::from((0, 10));
let b = Zq::from((10, 10));
assert_eq!(a, b);
}
#[test]
fn working_small() {
let zq_1 = Zq::from((10, 15));
let zq_2 = Zq::from((Z::from(10), Modulus::from(15)));
assert_eq!(zq_1, zq_2);
}
#[test]
fn working_large() {
let zq_1 = Zq::from((u64::MAX - 1, u64::MAX));
let zq_2 = Zq::from((&Z::from(u64::MAX - 1), Modulus::from(u64::MAX)));
assert_eq!(zq_1, zq_2);
}
#[test]
#[should_panic]
fn modulus_zero() {
let _ = Zq::from((10, 0));
}
#[test]
#[should_panic]
fn modulus_negative() {
let _ = Zq::from((10, -1));
}
}
#[cfg(test)]
mod tests_from_str {
use crate::integer_mod_q::Zq;
use std::str::FromStr;
#[test]
fn max_int_positive() {
assert!(Zq::from_str(&format!("{} mod {}", i64::MAX, u64::MAX)).is_ok());
}
#[test]
fn large_positive() {
assert!(Zq::from_str(&format!("{} mod {}", u64::MAX, u128::MAX)).is_ok());
}
#[test]
fn max_int_negative() {
assert!(Zq::from_str(&format!("-{} mod {}", i64::MAX, u64::MAX)).is_ok());
}
#[test]
fn large_negative() {
assert!(Zq::from_str(&format!("-{} mod {}", u64::MAX, u128::MAX)).is_ok());
}
#[test]
fn normal_value() {
assert!(Zq::from_str("42 mod 5").is_ok());
}
#[test]
fn whitespaces_work() {
assert!(Zq::from_str(" 42 mod 5").is_ok());
assert!(Zq::from_str("42 mod 5 ").is_ok());
assert!(Zq::from_str("42 mod 5").is_ok());
assert!(Zq::from_str("42 mod 5").is_ok());
}
#[test]
fn whitespaces_error() {
assert!(Zq::from_str("4 2 mod 5").is_err());
assert!(Zq::from_str("42 mo d 5").is_err());
assert!(Zq::from_str("42 mod 5 0").is_err());
}
#[test]
fn error_wrong_letters() {
assert!(Zq::from_str("hbrkt35itu3gg").is_err());
assert!(Zq::from_str("3-2 mod 3").is_err());
assert!(Zq::from_str("3 5").is_err());
assert!(Zq::from_str("3%5").is_err());
assert!(Zq::from_str("3/5 mod 3").is_err());
}
}
#[cfg(test)]
mod test_from_utf8 {
use super::Zq;
#[test]
fn not_enough_memory() {
let message = "some_long message with too many bytes";
let modulus = u32::MAX;
let value = Zq::from_utf8(message, modulus);
assert!(value.is_err());
}
#[test]
#[should_panic]
fn modulus_too_small() {
let message = "something";
let modulus = 1;
let _ = Zq::from_utf8(message, modulus);
}
}