Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
export class JacobianPoint<T> {
constructor(
public x: Field<T>,
public y: Field<T>,
public z: Field<T>,
public C: Constructor<T>
) {}
getZero() {
return new ProjectivePoint(this.C.ZERO, this.C.ONE, this.C.ZERO, this.C);
}
// Compare one point to another.
// ax * bz^2 == az^2 * bx and ay * bz^3 == by * az^3
equals(other: JacobianPoint<T>) {
const a = this;
const b = other;
const az2 = a.z.multiply(a.z);
const az3 = az2.multiply(a.z);
const bz2 = b.z.multiply(b.z);
const bz3 = bz2.multiply(b.z);
return (
a.x.multiply(bz2).equals(az2.multiply(b.x)) && a.y.multiply(bz3).equals(az3.multiply(b.y))
);
}
negative() {
return new JacobianPoint(this.x, this.y.negate(), this.z, this.C);
}
toString(isAffine = true) {
if (!isAffine) {
return `Point<x=${this.x}, y=${this.y}, z=${this.z}>`;
}
const [x, y] = this.toAffine();
return `Point<x=${x}, y=${y}>`;
}
toAffine(): [Field<T>, Field<T>] {
const z3Inv = this.z.pow(3n).invert();
return [this.x.multiply(this.z).multiply(z3Inv), this.y.multiply(z3Inv)];
}
double(): JacobianPoint<T> {
const X1 = this.x;
const Y1 = this.y;
const Z1 = this.z;
const A = X1.square();
const B = Y1.square();
const C = B.square();
const D = X1.add(B).square().subtract(A).subtract(C).multiply(2n);
const E = A.multiply(3n);
const F = E.square();
const X3 = F.subtract(D.multiply(2n));
const Y3 = E.multiply(D.subtract(X3)).subtract(C.multiply(8n));
const Z3 = Y1.multiply(Z1).multiply(2n);
if (Z3.isEmpty()) return this.getZero();
return new JacobianPoint(X3, Y3, Z3, this.C);
}
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-1998-cmo-2
// Cost: 12M + 4S + 6add + 1*2.
add(other: JacobianPoint<T>): JacobianPoint<T> {
if (!(other instanceof JacobianPoint)) throw new TypeError('Point#add: expected Point');
const X1 = this.x;
const Y1 = this.y;
const Z1 = this.z;
const X2 = other.x;
const Y2 = other.y;
const Z2 = other.z;
const Z1Z1 = Z1.pow(2n);
const Z2Z2 = Z2.pow(2n);
const U1 = X1.multiply(Z2Z2);
const U2 = X2.multiply(Z1Z1);
const S1 = Y1.multiply(Z2).multiply(Z2Z2);
const S2 = Y2.multiply(Z1).multiply(Z1Z1);
const H = U2.subtract(U1);
const rr = S2.subtract(S1).multiply(2n);
if (U1.equals(U2) && S1.equals(S2)) return this.double();
const I = H.multiply(2n).pow(2n);
const J = H.multiply(I);
const V = U1.multiply(I);
const X3 = rr.pow(2n).subtract(J).subtract(V.multiply(2n));
const Y3 = rr.multiply(V.subtract(X3)).subtract(S1.multiply(J).multiply(2n));
const Z3 = Z1.multiply(Z2).multiply(H).multiply(2n);
const p_inf = Z1.isEmpty();
const q_inf = Z2.isEmpty();
if (p_inf && q_inf) return this.getZero();
if (q_inf) return this;
if (p_inf) return other;
if (Z3.isEmpty()) return this.getZero();
return new JacobianPoint(X3, Y3, Z3, this.C);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.