use core::{ops::{Add, Neg}, fmt::Debug};
use cryptix_bigint::property::IsBigInt;
use cryptix_ecc::CurvePoint;
use cryptix_field::field::{montgomery::{MontgomeryOps, Montgomery}, Field, MulIdentity};
use cryptix_field::group::{AbelianGroup, CommunicativeAdd, Group, AddIdentity, AssociativeAdd};
use crate::{galoisfield::{fp2::Fp2Element, BN254, U256, FpElement, fp12::Fp12Element}, fp2};
use super::e1::BN254Fp;
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct BN254Fp2 {
pub x: Fp2Element,
pub y: Fp2Element,
pub z: Fp2Element
}
impl Debug for BN254Fp2 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "E2Point {{\n ")?;
write!(f, "x: fp2!(\n \"")?;
self.x.0.fmt(f)?;
write!(f, "\", \n \"")?;
self.x.1.fmt(f)?;
write!(f, "\"\n ),\n ")?;
write!(f, "y: fp2!(\n \"")?;
self.y.0.fmt(f)?;
write!(f, "\", \n \"")?;
self.y.1.fmt(f)?;
write!(f, "\"\n ),\n ")?;
write!(f, "z: fp2!(\n \"")?;
self.z.0.fmt(f)?;
write!(f, "\", \n \"")?;
self.z.1.fmt(f)?;
write!(f, "\"\n )\n}}")
}
}
impl BN254Fp2 {
pub const fn inf() -> Self {
Self { x: Fp2Element::ZERO, y: Fp2Element::ONE, z: Fp2Element::ZERO }
}
}
impl Add for BN254Fp2 {
type Output = BN254Fp2;
fn add(self, rhs: Self) -> Self::Output {
if self.at_inf() { return rhs }
if rhs.at_inf() { return self }
let mut t = Self::inf();
let t0 = self.x.mont_mul(rhs.x);
let t1 = self.y.mont_mul(rhs.y);
let t2 = self.z.mont_mul(rhs.z);
let t3 = self.x + self.y;
let t4 = rhs.x + rhs.y;
let t3 = t3.mont_mul(t4);
let t4 = t0 + t1;
let t3 = t3 - t4;
let t4 = self.y + self.z;
t.x = rhs.y + rhs.z;
let t4 = t4.mont_mul(t.x);
t.x = t1 + t2;
let t4 = t4 - t.x;
t.x = self.x + self.z;
t.y = rhs.x + rhs.z;
t.x = t.x.mont_mul(t.y);
t.y = t0 + t2;
t.y = t.x - t.y;
t.x = t0 + t0;
let t0 = t.x + t0;
let t2 = t2.mul_3b();
t.z = t1 + t2;
let t1 = t1 - t2;
t.y = t.y.mul_3b();
t.x = t4.mont_mul(t.y);
let t2 = t3.mont_mul(t1);
t.x = t2 - t.x;
t.y = t.y.mont_mul(t0);
let t1 = t1.mont_mul(t.z);
t.y = t1 + t.y;
let t0 = t0.mont_mul(t3);
t.z = t.z.mont_mul(t4) + t0;
t
}
}
impl AssociativeAdd for BN254Fp2 { }
impl CommunicativeAdd for BN254Fp2 { }
impl AddIdentity for BN254Fp2 {
const ADD_IDENTITY: Self = Self::inf();
}
impl Neg for BN254Fp2 {
type Output = Self;
fn neg(self) -> Self::Output {
Self { x: self.x, y: -self.y, z: self.z }
}
}
impl Group for BN254Fp2 { }
impl AbelianGroup for BN254Fp2 { }
impl CurvePoint for BN254Fp2 {
type MulScalar = U256;
const GENERATOR: Self = BN254Fp2 {
x: fp2!(
"173F71DE61DF5B55EF7AB941DCD46337BB92F0233D01BC7CAF45AAAF63659E66",
"10C76BD06630C4E91FCE93827A42E357413D1E26BC087B6A389BBB43D0D2F4E7"
),
y: fp2!(
"182C7A581C2D120D9215E25E884B2CC75A0FCF130C7D101225D0B13674482015",
"1598CFFE781D1A201E0D27E0927F85986CE6262AA3A25124FBB0D5E1FCB5D7AA"
),
z: fp2!(
"212BA4F27FFFFFF5A2C62EFFFFFFFFCDB939FFFFFFFFFF8A15FFFFFFFFFFFF8E",
"0000000000000000000000000000000000000000000000000000000000000000"
)
};
fn double(self) -> Self {
if self.at_inf() { return self }
let mut t = Self::inf();
let t0 = self.y.mont_sqr();
t.z = t0 + t0;
t.z = t.z + t.z;
t.z = t.z + t.z;
let t1 = self.y.mont_mul(self.z);
let t2 = self.z.mont_sqr().mul_3b();
t.x = t2.mont_mul(t.z);
t.y = t0 + t2;
t.z = t1.mont_mul(t.z);
let t1 = t2 + t2;
let t2 = t1 + t2;
let t0 = t0 - t2;
t.y = t0.mont_mul(t.y) + t.x;
let t1 = self.x.mont_mul(self.y);
t.x = t0.mont_mul(t1);
t.x = t.x + t.x;
t
}
fn scalar_mul(self, k: U256) -> Self {
const W: usize = 4;
const LEN: usize = 16;
const MASK: <U256 as IsBigInt>::Dig = 0xf;
let mut kp = [BN254Fp2::inf(); LEN];
kp[1] = self;
kp[2] = self.double();
for i in 3..LEN {
if i & 1 == 0 {
kp[i] = kp[i >> 1].double();
} else {
kp[i] = kp[i - 1].mix_add(self);
}
debug_assert!(kp[i].on_curve())
}
let ki = ((k[U256::DIG_LEN - 1] >> (W * (U256::DIG_BIT_LEN / W - 1))) & MASK) as usize;
let mut q = kp[ki];
for j in (0..(U256::DIG_BIT_LEN / W - 1)).rev() {
let ki = ((k[U256::DIG_LEN - 1] >> (W * j)) & MASK) as usize;
for _ in 0..W {
q = q.double();
}
q = q + kp[ki]
}
for i in (0..(U256::DIG_LEN - 1)).rev() {
for j in (0..(U256::DIG_BIT_LEN / W)).rev() {
let ki = ((k[i] >> (W * j)) & MASK) as usize;
for _ in 0..W {
q = q.double();
}
q = q + kp[ki]
}
}
q
}
fn at_inf(&self) -> bool {
self.z.is_zero()
}
fn on_curve(&self) -> bool {
let x3 = self.x.mont_sqr().mont_mul(self.x);
let z3 = self.z.mont_sqr().mont_mul(self.z);
let z3mi = z3.mont_mul(BN254::B_DIV_XI_MONT);
let y2z = self.y.mont_sqr().mont_mul(self.z);
x3 + z3mi == y2z
}
fn normalize(self) -> Self {
let t = self.z.mont_inv();
let x = self.x.mont_mul(t);
let y = self.y.mont_mul(t);
Self { x, y, z: Fp2Element(BN254::R_P, FpElement::ZERO) }
}
fn mont_form(self) -> Self {
Self {
x: self.x.mont_form(),
y: self.y.mont_form(),
z: self.z.mont_form()
}
}
fn mont_rdc(self) -> Self {
Self {
x: self.x.mont_rdc(),
y: self.y.mont_rdc(),
z: self.z.mont_rdc()
}
}
}
impl BN254Fp2 {
pub fn mix_add(self, mut rhs: Self) -> Self {
if rhs.z != BN254::R_P.into() {
rhs = rhs.normalize();
}
if self.at_inf() { return rhs }
if rhs.at_inf() { return self }
let mut t = Self::inf();
let t0 = self.x.mont_mul(rhs.x);
let t1 = self.y.mont_mul(rhs.y);
let t3 = rhs.x + rhs.y;
let t4 = self.x + self.y;
let t3 = t3.mont_mul(t4);
let t4 = t0 + t1;
let t3 = t3 - t4;
let t4 = self.z.mont_mul(rhs.y);
let t4 = self.y + t4;
t.y = self.z.mont_mul(rhs.x);
t.y = t.y + self.x;
t.x = t0 + t0;
let t0 = t.x + t0;
let t2 = self.z.mul_3b();
t.z = t1 + t2;
let t1 = t1 - t2;
t.y = t.y.mul_3b();
t.x = t.y.mont_mul(t4);
let t2 = t3.mont_mul(t1);
t.x = t2 - t.x;
t.y = t.y.mont_mul(t0);
let t1 = t1.mont_mul(t.z);
t.y = t1 + t.y;
let t0 = t0.mont_mul(t3);
t.z = t.z.mont_mul(t4) + t0;
t
}
pub fn dbl_line(mut self, p: BN254Fp) -> (Self, Fp12Element) {
let mut val = Fp12Element::ZERO;
val.1.0 = self.x.mont_sqr();
let a = self.x.mont_mul(self.y).hlv();
let b = self.y.mont_sqr();
let c = self.z.mont_sqr();
val.0.1 = c.mont_mul(BN254::B_DIV_XI_MONT);
let f = val.0.1 + val.0.1;
val.0.1 = val.0.1 + f;
let f = val.0.1 + val.0.1 + val.0.1;
self.x = (b - f).mont_mul(a); val.0.0 = (self.y + self.z).mont_sqr() - b - c;
let g = (b + f).hlv();
self.z = b.mont_mul(val.0.0); self.y = g.mont_sqr();
let a = val.0.1.mont_sqr();
self.y = self.y - a - a - a;
val.0.0 = -val.0.0.mont_mul_fp(p.y);
val.0.1 = val.0.1 - b;
val.1.0 = val.1.0.mont_mul_fp(p.x);
val.1.0 = val.1.0 + val.1.0 + val.1.0;
(self, val)
}
pub fn mix_add_line(mut self, mut rhs: Self, p: BN254Fp) -> (Self, Fp12Element) {
if rhs.z != BN254::R_P.into() {
rhs = rhs.normalize();
}
let mut val = Fp12Element::ZERO;
let a = self.z.mont_mul(rhs.y);
let b = self.z.mont_mul(rhs.x);
let theta = self.y - a;
let lambda = self.x - b;
let c = theta.mont_sqr();
let d = lambda.mont_sqr();
let e = d.mont_mul(lambda);
let f = self.z.mont_mul(c);
let g = self.x.mont_mul(d);
let h = e + f - g - g;
self.x = lambda.mont_mul(h); let i = self.y.mont_mul(e);
self.y = (g - h).mont_mul(theta) - i; self.z = self.z.mont_mul(e);
val.0.0 = lambda.mont_mul_fp(p.y);
val.1.0 = -theta.mont_mul_fp(p.x);
val.0.1 = theta.mont_mul(rhs.x) - lambda.mont_mul(rhs.y);
(self, val)
}
pub fn map_frob(self) -> Self {
Self {
x: self.x.conjugate().mont_mul(BN254::XI_MONT[1]),
y: self.y.conjugate().mont_mul(BN254::XI_MONT[2]),
z: self.z.conjugate()
}
}
pub fn map2_frob(self) -> Self {
Self {
x: self.x.mont_mul_fp(BN254::P2_FROB_MAP_VAL[1]),
y: self.y.mont_mul_fp(BN254::P2_FROB_MAP_VAL[2]),
z: self.z
}
}
}