anothertls 0.1.3

Yet another TLS implementation, but written from scratch (including the crypto) in pure Rust - of course.
Documentation
/*
 * Copyright (c) 2023, Tobias Müller <git@tsmr.eu>
 *
 */

use super::rem_euclid;
use crate::crypto::ellipticcurve::math::IBig;
use crate::crypto::ellipticcurve::Curve;
use crate::crypto::ellipticcurve::JacobianPoint;
use ibig::ibig;

pub fn jacobian_double(p: &JacobianPoint, curve: &Curve) -> JacobianPoint {
    let a = curve.a.clone();
    let prime = &curve.p;

    if p.y == ibig!(0) {
        return JacobianPoint {
            x: ibig!(0),
            y: ibig!(0),
            z: ibig!(0),
        };
    }

    let ysq = p.y.pow(2);
    let s = rem_euclid(&(p.x.clone() * &ibig!(4) * ysq.clone()), prime);
    let m = rem_euclid(
        &(p.x.clone().pow(2) * &ibig!(3) + a * p.z.clone().pow(4)),
        prime,
    );
    let nx = rem_euclid(&(m.pow(2) - &ibig!(2) * s.clone()), prime);
    let ny = rem_euclid(&(m * (s - nx.clone()) - &ibig!(8) * ysq.pow(2)), prime);
    let nz = rem_euclid(&(p.y.clone() * p.z.clone() * &ibig!(2)), prime);

    JacobianPoint {
        x: nx,
        y: ny,
        z: nz,
    }
}

pub fn jacobian_add(p: &JacobianPoint, q: &JacobianPoint, curve: &Curve) -> JacobianPoint {
    if p.y == ibig!(0) {
        return q.clone();
    }
    if q.y == ibig!(0) {
        return p.clone();
    }

    let u1 = rem_euclid(&(p.x.clone() * q.z.pow(2)), &curve.p);
    let u2 = rem_euclid(&(q.x.clone() * p.z.pow(2)), &curve.p);
    let s1 = rem_euclid(&(p.y.clone() * q.z.pow(3)), &curve.p);
    let s2 = rem_euclid(&(q.y.clone() * p.z.pow(3)), &curve.p);

    if u1 == u2 {
        if s1 != s2 {
            return JacobianPoint::new(0, 0, 1);
        }
        return jacobian_double(p, curve);
    }

    let h = rem_euclid(&(u2 - u1.clone()), &curve.p);
    let r = rem_euclid(&(s2 - s1.clone()), &curve.p);
    let h2 = rem_euclid(&(h.clone() * h.clone()), &curve.p);
    let h3 = rem_euclid(&(h.clone() * h2.clone()), &curve.p);
    let u1_h2 = rem_euclid(&(u1 * h2), &curve.p);
    let x = rem_euclid(
        &(r.pow(2) - h3.clone() - IBig::from(2) * u1_h2.clone()),
        &curve.p,
    );
    let y = rem_euclid(&(r * (u1_h2 - &x) - s1 * h3), &curve.p);
    let z = rem_euclid(&(h * p.z.clone() * q.z.clone()), &curve.p);

    JacobianPoint { x, y, z }
}

pub fn jacobian_multiply(p: &JacobianPoint, n: IBig, curve: &Curve) -> JacobianPoint {
    if p.y == ibig!(0) || n == ibig!(0) {
        return JacobianPoint::new(0, 0, 1);
    }

    if n == ibig!(1) {
        return p.clone();
    }

    if n < ibig!(0) || n >= curve.n {
        return jacobian_multiply(p, rem_euclid(&n, &curve.n), curve);
    }

    let q = jacobian_double(&jacobian_multiply(p, n.clone() / 2, curve), curve);

    if rem_euclid(&n, &ibig!(2)) == ibig!(0) {
        return q;
    }

    jacobian_add(&q, p, curve)
}