use super::Zq;
use crate::traits::Pow;
use flint_sys::{fmpz::fmpz_is_zero, fmpz_mod::fmpz_mod_is_one};
impl Zq {
pub fn inverse(&self) -> Option<Zq> {
self.pow(-1).ok()
}
pub fn is_zero(&self) -> bool {
1 == unsafe { fmpz_is_zero(&self.value.value) }
}
pub fn is_one(&self) -> bool {
1 == unsafe { fmpz_mod_is_one(&self.value.value, self.modulus.get_fmpz_mod_ctx_struct()) }
}
}
#[cfg(test)]
mod test_inv {
use super::Zq;
#[test]
fn small_values() {
let val_0 = Zq::from((4, 7));
let val_1 = Zq::from((-2, 7));
let inv_0 = val_0.inverse().unwrap();
let inv_1 = val_1.inverse().unwrap();
assert_eq!(Zq::from((2, 7)), inv_0);
assert_eq!(Zq::from((3, 7)), inv_1);
}
#[test]
fn large_values() {
let val_0 = Zq::from((i64::MAX, u64::MAX));
let val_1 = Zq::from((i64::MIN, u64::MAX));
let inv_0 = val_0.inverse().unwrap();
let inv_1 = val_1.inverse().unwrap();
assert_eq!(Zq::from((18446744073709551613_u64, u64::MAX)), inv_0);
assert_eq!(Zq::from((18446744073709551613_u64, u64::MAX)), inv_1);
}
#[test]
fn no_inverse_returns_none() {
let val_0 = Zq::from((4, 8));
let val_1 = Zq::from((3, 9));
let val_2 = Zq::from((0, 7));
assert!(val_0.inverse().is_none());
assert!(val_1.inverse().is_none());
assert!(val_2.inverse().is_none());
}
}
#[cfg(test)]
mod test_is_zero {
use super::Zq;
use std::str::FromStr;
#[test]
fn zero_detection() {
let zero = Zq::from((0, 7));
assert!(zero.is_zero());
}
#[test]
fn zero_rejection() {
let small = Zq::from((4, 9));
let large =
Zq::from_str(&format!("{} mod {}", (u128::MAX - 1) / 2 + 1, u128::MAX)).unwrap();
assert!(!small.is_zero());
assert!(!large.is_zero());
}
}
#[cfg(test)]
mod test_is_one {
use super::Zq;
use std::str::FromStr;
#[test]
fn one_detection() {
let one = Zq::from((8, 7));
assert!(one.is_one());
}
#[test]
fn one_rejection() {
let small = Zq::from((12, 7));
let large =
Zq::from_str(&format!("{} mod {}", (u128::MAX - 1) / 2 + 2, u128::MAX)).unwrap();
assert!(!small.is_one());
assert!(!large.is_one());
}
}