use super::{AddComponents, EcCurve, EcPoint, JacPoint};
use crate::fp::{Fp, Fp2, FpBackend};
use subtle::Choice;
#[inline]
fn select_jac_point<L: FpBackend>(p1: &JacPoint<L>, p2: &JacPoint<L>, ctl: Choice) -> JacPoint<L> {
JacPoint {
x: Fp2::select(&p1.x, &p2.x, ctl),
y: Fp2::select(&p1.y, &p2.y, ctl),
z: Fp2::select(&p1.z, &p2.z, ctl),
}
}
impl<L: FpBackend> JacPoint<L> {
#[inline]
pub fn ct_equal(&self, other: &Self) -> Choice {
let t0 = other.z.sqr();
let t2 = self.x.mul(&t0); let t1 = self.z.sqr();
let t3 = other.x.mul(&t1); let dx = t2.sub(&t3);
let t0 = t0.mul(&other.z);
let t0 = self.y.mul(&t0); let t1 = t1.mul(&self.z);
let t1 = other.y.mul(&t1); let dy = t0.sub(&t1);
dy.ct_is_zero() & dx.ct_is_zero()
}
#[inline]
pub fn to_xz(&self) -> EcPoint<L> {
let x = self.x.clone();
let z = self.z.sqr();
let c1 = x.ct_is_zero();
let c2 = z.ct_is_zero();
let one = Fp2::<L>::one();
let x = Fp2::select(&x, &one, c1 & c2);
EcPoint { x, z }
}
#[inline]
pub fn neg(&self) -> Self {
Self {
x: self.x.clone(),
y: self.y.neg(),
z: self.z.clone(),
}
}
#[inline]
pub fn to_ws(&self, curve: &EcCurve<L>) -> (JacPoint<L>, Fp2<L>, Fp2<L>) {
let mut ao3 = Fp2::<L>::zero();
let t;
if !bool::from(curve.a.ct_is_zero()) {
ao3.re = curve.a.re.div3();
ao3.im = curve.a.im.div3();
let z2 = self.z.sqr();
let qx = ao3.mul(&z2);
let qx = qx.add(&self.x);
let z4 = z2.sqr();
let a = ao3.mul(&curve.a);
let one = Fp::<L>::one();
let a_re = one.sub(&a.re);
let a_im = a.im.neg();
let a = Fp2 { re: a_re, im: a_im };
t = z4.mul(&a);
let q = JacPoint {
x: qx,
y: self.y.clone(),
z: self.z.clone(),
};
(q, t, ao3)
} else {
let z2 = self.z.sqr();
t = z2.sqr();
let q = JacPoint {
x: self.x.clone(),
y: self.y.clone(),
z: self.z.clone(),
};
(q, t, ao3)
}
}
#[inline]
pub fn from_ws(p: &JacPoint<L>, ao3: &Fp2<L>, curve: &EcCurve<L>) -> JacPoint<L> {
let x = if !bool::from(curve.a.ct_is_zero()) {
let t = p.z.sqr();
let t = t.mul(ao3);
p.x.sub(&t)
} else {
p.x.clone()
};
JacPoint {
x,
y: p.y.clone(),
z: p.z.clone(),
}
}
}
#[inline]
pub fn jac_dbl<L: FpBackend>(p: &JacPoint<L>, ac: &EcCurve<L>) -> JacPoint<L> {
let is_identity = p.x.ct_is_zero() & p.z.ct_is_zero();
let t0 = p.x.sqr(); let t1 = t0.add(&t0);
let t0 = t0.add(&t1); let t1 = p.z.sqr(); let t2 = p.x.mul(&ac.a);
let t2 = t2.add(&t2); let t2 = t1.add(&t2); let t2 = t1.mul(&t2); let t2 = t0.add(&t2);
let qz = p.y.mul(&p.z);
let qz = qz.add(&qz);
let t0 = qz.sqr();
let t0 = t0.mul(&ac.a); let t1 = p.y.sqr();
let t1 = t1.add(&t1); let t3 = p.x.add(&p.x); let t3 = t1.mul(&t3); let qx = t2.sqr(); let qx = qx.sub(&t0); let qx = qx.sub(&t3);
let qx = qx.sub(&t3); let qy = t3.sub(&qx); let qy = qy.mul(&t2); let t1 = t1.sqr(); let qy = qy.sub(&t1);
let qy = qy.sub(&t1);
let qx = Fp2::select(&qx, &p.x, is_identity);
let qz = Fp2::select(&qz, &p.z, is_identity);
JacPoint {
x: qx,
y: qy,
z: qz,
}
}
#[inline]
pub fn jac_dbl_ws<L: FpBackend>(p: &JacPoint<L>, t: &Fp2<L>) -> (JacPoint<L>, Fp2<L>) {
let is_identity = p.x.ct_is_zero() & p.z.ct_is_zero();
let xx = p.x.sqr();
let c = p.y.sqr();
let c = c.add(&c); let cc = c.sqr(); let r = cc.add(&cc); let s = p.x.add(&c);
let s = s.sqr();
let s = s.sub(&xx);
let s = s.sub(&cc); let m = xx.add(&xx);
let m = m.add(&xx);
let m = m.add(t); let qx = m.sqr();
let qx = qx.sub(&s);
let qx = qx.sub(&s); let qz = p.y.mul(&p.z);
let qz = qz.add(&qz); let qy = s.sub(&qx);
let qy = qy.mul(&m);
let qy = qy.sub(&r); let u = t.mul(&r);
let u = u.add(&u);
let qx = Fp2::select(&qx, &p.x, is_identity);
let qz = Fp2::select(&qz, &p.z, is_identity);
(
JacPoint {
x: qx,
y: qy,
z: qz,
},
u,
)
}
#[inline]
pub fn jac_add<L: FpBackend>(p: &JacPoint<L>, q: &JacPoint<L>, ac: &EcCurve<L>) -> JacPoint<L> {
let ctl1 = p.z.ct_is_zero();
let ctl2 = q.z.ct_is_zero();
let t0 = p.z.sqr(); let t1 = q.z.sqr();
let v1 = t1.mul(&q.z); let t2 = t0.mul(&p.z); let v1 = v1.mul(&p.y); let t2 = t2.mul(&q.y); let dy_ord = t2.sub(&v1);
let u2 = t0.mul(&q.x); let u1 = t1.mul(&p.x); let dx_ord = u2.sub(&u1);
let t1_dbl = p.y.add(&p.y); let t2_dbl = {
let two_a = ac.a.add(&ac.a);
let t2 = two_a.mul(&p.x); let t2 = t2.add(&t0); let t2 = t2.mul(&t0); let x_sq = p.x.sqr();
let t2 = t2.add(&x_sq);
let t2 = t2.add(&x_sq);
let t2 = t2.add(&x_sq); t2.mul(&q.z) };
let ctl = dx_ord.ct_is_zero() & dy_ord.ct_is_zero();
let dx = Fp2::select(&dx_ord, &t1_dbl, ctl);
let dy = Fp2::select(&dy_ord, &t2_dbl, ctl);
let t0 = p.z.mul(&q.z); let t1 = t0.sqr(); let t2 = dx.sqr(); let t3 = dy.sqr();
let rx = ac.a.mul(&t1);
let rx = rx.add(&u1);
let rx = rx.add(&u2);
let rx = rx.mul(&t2);
let rx = t3.sub(&rx);
let ry = u1.mul(&t2);
let ry = ry.sub(&rx);
let ry = ry.mul(&dy);
let t3 = t2.mul(&dx); let t3 = t3.mul(&v1); let ry = ry.sub(&t3);
let rz = dx.mul(&t0);
let mut r = JacPoint {
x: rx,
y: ry,
z: rz,
};
r = select_jac_point(&r, q, ctl1);
r = select_jac_point(&r, p, ctl2);
r
}
#[inline]
pub fn jac_to_xz_add_components<L: FpBackend>(
p: &JacPoint<L>,
q: &JacPoint<L>,
ac: &EcCurve<L>,
) -> AddComponents<L> {
let t0 = p.z.sqr(); let t1 = q.z.sqr(); let t2 = p.x.mul(&t1); let t3 = t0.mul(&q.x); let t4 = p.y.mul(&q.z);
let t4 = t4.mul(&t1); let t5 = p.z.mul(&q.y);
let t5 = t5.mul(&t0); let t0 = t0.mul(&t1); let t6 = t4.mul(&t5); let v = t6.add(&t6); let t4 = t4.sqr(); let t5 = t5.sqr(); let t4 = t4.add(&t5);
let t5 = t2.add(&t3); let t6 = t3.add(&t3); let t6 = t5.sub(&t6); let t6 = t6.sqr(); let t1 = ac.a.mul(&t0); let t1 = t5.add(&t1); let t1 = t1.mul(&t6); let u = t4.sub(&t1);
let w = t6.mul(&t0);
AddComponents { u, v, w }
}