use core::ops::{Add, Sub, Mul, Neg};
use cryptix_bigint::property::IsBigInt;
use cryptix_field::field::montgomery::Montgomery;
use cryptix_field::group::*;
use cryptix_field::ring::*;
use cryptix_field::field::*;
use cryptix_field::field::montgomery::MontgomeryOps;
use super::{U256, BN254, FpElement};
use super::fp2::Fp2Element;
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Fp4Element(pub Fp2Element, pub Fp2Element);
impl core::fmt::Debug for Fp4Element {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "fp4!(\n \"")?;
self.0.0.fmt(f)?;
write!(f, "\", \n \"")?;
self.0.1.fmt(f)?;
write!(f, "\", \n \"")?;
self.1.0.fmt(f)?;
write!(f, "\", \n \"")?;
self.1.1.fmt(f)?;
write!(f, "\"\n)\n ")
}
}
impl AbelianGroup for Fp4Element { }
impl Group for Fp4Element { }
impl Add for Fp4Element {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1)
}
}
impl Sub for Fp4Element{
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl AddIdentity for Fp4Element{
const ADD_IDENTITY: Self = Self(Fp2Element::ZERO, Fp2Element::ZERO);
}
impl Neg for Fp4Element {
type Output = Self;
fn neg(self) -> Self::Output {
Self(-self.0, -self.1)
}
}
impl AssociativeAdd for Fp4Element { }
impl CommunicativeAdd for Fp4Element { }
impl Ring for Fp4Element { }
impl Mul for Fp4Element {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
self.mont_mul(rhs).mont_form()
}
}
impl AssociativeMul for Fp4Element { }
impl DistributiveMul for Fp4Element { }
impl MulIdentity for Fp4Element {
const MUL_IDENTITY: Self = Self(Fp2Element::ONE, Fp2Element::ZERO);
}
impl CommunicativeMul for Fp4Element { }
impl MulInverse for Fp4Element {
fn mul_inv(self) -> Self {
self.mont_inv().mont_mul_fp(BN254::R_INV_P)
}
}
impl Field for Fp4Element {
fn hlv(self) -> Self {
Self(self.0.hlv(), self.1.hlv())
}
fn is_zero(&self) -> bool {
self.0.is_zero() && self.1.is_zero()
}
}
impl From<FpElement> for Fp4Element {
fn from(value: FpElement) -> Self {
Self(Fp2Element::from(value), Fp2Element::ZERO)
}
}
impl MontgomeryOps<U256, BN254> for Fp4Element {
fn mont_mul(self, rhs: Self) -> Self {
let (a0, b0) = (self.0, self.1);
let (a1, b1) = (rhs.0, rhs.1);
let a0a1 = a0.mont_mul(a1);
let b0b1 = b0.mont_mul(b1);
Self(
a0a1 + b0b1.mul_xi(),
(a0 + b0).mont_mul(a1 + b1) - a0a1 - b0b1
)
}
fn mont_sqr(self) -> Self {
let (a, b) = (self.0, self.1);
let ab = a.mont_mul(b);
Self(
(a + b.mul_xi()).mont_mul(a + b) - ab - ab.mul_xi(),
ab + ab
)
}
fn mont_inv(self) -> Self {
let t = (self.0.mont_sqr() - self.1.mont_sqr().mul_xi()).mont_inv();
Self(self.0.mont_mul(t), -self.1.mont_mul(t))
}
fn mont_mul_fp(self, rhs: FpElement) -> Self {
Self(self.0.mont_mul_fp(rhs), self.1.mont_mul_fp(rhs))
}
fn mont_rdc(self) -> Self {
Self(self.0.mont_rdc(), self.1.mont_rdc())
}
}
impl Fp4Element {
pub fn mul_s(self) -> Self {
Self(self.1.mul_xi(), self.0)
}
pub fn sparse_mul(self, rhs: Fp2Element) -> Self {
Self(self.0.mont_mul(rhs), self.1.mont_mul(rhs))
}
pub fn conjugate(self) -> Self {
Self(self.0, -self.1)
}
pub fn map_frob(self) -> Self {
Self(self.0.map_frob(), self.1.map_frob().mont_mul(BN254::XI_MONT[2]))
}
}
#[cfg(feature = "rand")]
impl Fp4Element {
pub fn rand(rng: &mut impl rand_core::CryptoRngCore) -> Self {
Self(Fp2Element::rand(rng), Fp2Element::rand(rng))
}
}
impl From<Fp4Element> for [u8; U256::BYTE_LEN * 4] {
fn from(val: Fp4Element) -> Self {
let mut buf = [0_u8; U256::BYTE_LEN * 4];
let tmp: [u8; U256::BYTE_LEN * 2] = val.0.into();
buf[..U256::BYTE_LEN * 2].copy_from_slice(&tmp);
let tmp: [u8; U256::BYTE_LEN * 2] = val.1.into();
buf[U256::BYTE_LEN * 2..U256::BYTE_LEN * 4].copy_from_slice(&tmp);
buf
}
}