use core::ops::{Add, Neg};
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::{FpElement, BN254, U256}, fp};
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct BN254Fp {
pub x: FpElement,
pub y: FpElement,
pub z: FpElement
}
impl core::fmt::Debug for BN254Fp {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "E1Point {{\n ")?;
write!(f, "x: fp!(\"")?;
self.x.fmt(f)?;
write!(f, "\"), \n ")?;
write!(f, "y: fp!(\"")?;
self.y.fmt(f)?;
write!(f, "\"), \n ")?;
write!(f, "z: fp!(\"")?;
self.z.fmt(f)?;
write!(f, "\"), \n}}")
}
}
impl BN254Fp {
pub const fn inf() -> Self {
Self { x: FpElement::ZERO, y: FpElement::ONE, z: FpElement::ZERO }
}
}
impl Add for BN254Fp {
type Output = BN254Fp;
fn add(self, rhs: Self) -> Self::Output {
if self.at_inf() {
return rhs
}
if rhs.at_inf() {
return self
}
let t1 = self.z.mont_sqr(); let t2 = self.z.mont_mul(t1);
let t1 = t1.mont_mul(rhs.x);
let t2 = t2.mont_mul(rhs.y);
let t3 = rhs.z; let y = self.y.mont_mul(t3);
let z = self.z.mont_mul(t3);
let t3 = t3.mont_sqr();
let y = y.mont_mul(t3);
let x = self.x.mont_mul(t3); let t1 = t1 - x;
let z = z.mont_mul(t1);
let t2 = t2 - y;
let t3 = t1.mont_sqr();
let t1 = t1.mont_mul(t3); let t3 = t3.mont_mul(x);
let x = t2.mont_sqr();
let x = x - t3 - t3 - t1;
let t3 = (t3 - x).mont_mul(t2);
let t1 = t1.mont_mul(y);
let y = t3 - t1;
Self { x, y, z }
}
}
impl AssociativeAdd for BN254Fp { }
impl CommunicativeAdd for BN254Fp { }
impl AddIdentity for BN254Fp {
const ADD_IDENTITY: Self = Self::inf();
}
impl Neg for BN254Fp {
type Output = Self;
fn neg(self) -> Self::Output {
Self { x: self.x, y: -self.y, z: self.z }
}
}
impl Group for BN254Fp { }
impl AbelianGroup for BN254Fp { }
impl CurvePoint for BN254Fp {
type MulScalar = U256;
const GENERATOR: Self = BN254Fp {
x: fp!("03F7BF8FC000000C176E1E800000003AA7E70000000000899100000000000085"),
y: fp!("212BA4F27FFFFFF5A2C62EFFFFFFFFCDB939FFFFFFFFFF8A15FFFFFFFFFFFF8E"),
z: fp!("212BA4F27FFFFFF5A2C62EFFFFFFFFCDB939FFFFFFFFFF8A15FFFFFFFFFFFF8E")
};
fn double(self) -> Self {
if self.at_inf() {
return self
}
let t2 = self.x.mont_sqr();
let t1 = t2 + t2 + t2;
let y = self.y + self.y;
let z = self.z.mont_mul(y);
let y = y.mont_sqr();
let t2 = y.mont_mul(self.x);
let y = y.mont_sqr().hlv();
let x = t1.mont_sqr() - t2 - t2;
let t2 = t2 - x;
let t1 = t1.mont_mul(t2);
let y = t1 - y;
Self { x, y, z }
}
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 = [BN254Fp::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 y2 = self.y.mont_sqr();
let x3 = self.x.mont_sqr();
let x3 = x3.mont_mul(self.x);
let z6 = self.z.mont_sqr();
let z6 = self.z.mont_mul(z6);
let z6 = z6.mont_sqr();
let r = (z6 + z6 + x3).mont_rdc();
let l = y2.mont_rdc();
l == r
}
fn normalize(self) -> Self {
let t1 = self.z.mont_inv();
let t2 = t1.mont_sqr();
let x = self.x.mont_mul(t2);
let t2 = t2.mont_mul(t1);
let y = self.y.mont_mul(t2);
Self { x, y, z: BN254::R_P }
}
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 BN254Fp {
pub fn mix_add(self, mut rhs: Self) -> Self {
if rhs.z != BN254::R_P {
rhs = rhs.normalize();
}
if self.at_inf() { return rhs }
if rhs.at_inf() { return self }
let t1 = self.z.mont_sqr(); let t2 = self.z.mont_mul(t1);
let t1 = t1.mont_mul(rhs.x);
let t2 = t2.mont_mul(rhs.y);
let t1 = t1 - self.x; let z = self.z.mont_mul(t1);
let t2 = t2 - self.y;
let t3 = t1.mont_sqr();
let t1 = t1.mont_mul(t3);
let t3 = t3.mont_mul(self.x);
let x = t2.mont_sqr();
let x = x - t3 - t3 - t1;
let t3 = t3 - x;
let t3 = t3.mont_mul(t2);
let t1 = t1.mont_mul(self.y);
let y = t3 - t1;
Self { x, y, z }
}
}