use crate::ConstChoice;
use core::ops::Neg;
use subtle::{Choice, ConstantTimeEq};
#[derive(Debug, Copy, Clone)]
#[repr(i8)]
pub enum JacobiSymbol {
Zero = 0,
One = 1,
MinusOne = -1,
}
impl JacobiSymbol {
pub const fn is_zero(&self) -> ConstChoice {
ConstChoice::from_i64_eq(*self as i8 as i64, 0)
}
pub const fn is_one(&self) -> ConstChoice {
ConstChoice::from_i64_eq(*self as i8 as i64, 1)
}
pub const fn is_minus_one(&self) -> ConstChoice {
ConstChoice::from_i64_eq(*self as i8 as i64, -1)
}
pub const fn neg(self) -> Self {
match self {
Self::Zero => Self::Zero,
Self::One => Self::MinusOne,
Self::MinusOne => Self::One,
}
}
pub(crate) const fn from_i8(value: i8) -> Self {
match value {
0 => Self::Zero,
1 => Self::One,
-1 => Self::MinusOne,
_ => panic!("invalid value for Jacobi symbol"),
}
}
}
impl ConstantTimeEq for JacobiSymbol {
fn ct_eq(&self, other: &Self) -> Choice {
(*self as i8).ct_eq(&(*other as i8))
}
}
impl Eq for JacobiSymbol {}
impl PartialEq for JacobiSymbol {
fn eq(&self, other: &Self) -> bool {
bool::from(self.ct_eq(other))
}
}
impl From<JacobiSymbol> for i8 {
fn from(symbol: JacobiSymbol) -> i8 {
symbol as i8
}
}
impl Neg for JacobiSymbol {
type Output = Self;
fn neg(self) -> Self {
match self {
Self::Zero => Self::Zero,
Self::One => Self::MinusOne,
Self::MinusOne => Self::One,
}
}
}