``````package Crypt::Perl::ECDSA::EC::Point;

use strict;
use warnings;

#----------------------------------------------------------------------
# NOTE TO SELF: This module’s internal coordinates are
# homogeneous/projective coordinates, not Cartesian.
#----------------------------------------------------------------------

use Crypt::Perl::BigInt ();

my (\$bi1, \$bi2, \$bi3);

END {
undef \$bi1, \$bi2, \$bi3;
}

sub new_infinity {
my (\$class) = @_;

return \$class->new( undef, undef );
}

#\$curve is ECCurve
#\$x and \$y are “ECFieldElement”
#\$z isa bigint (?)
sub new {
my (\$class, \$curve, \$x, \$y, \$z) = @_;

\$bi1 ||= Crypt::Perl::BigInt->new(1);
\$bi2 ||= Crypt::Perl::BigInt->new(2);
\$bi3 ||= Crypt::Perl::BigInt->new(3);

my \$self = {
curve => \$curve,
x => \$x,
y => \$y,

# Generally z won’t be given since we expect
# Cartesian coordinates as input. But accepting
# z allows this constructor to receive Jacobi
# coordinates as well.
z => \$z || \$bi1->copy(),

zinv => undef,
};

return bless \$self, \$class;
}

sub is_infinity {
my (\$self) = @_;

return 1 if !defined \$self->{'x'} && !defined \$self->{'y'};

return( (\$self->{'z'}->is_zero() && !\$self->{'y'}->to_bigint()->is_zero()) || 0 );
}

#returns ECFieldElement (Cartesian)
sub get_x {
my (\$self) = @_;

return \$self->_get_x_or_y('x');
}

#returns ECFieldElement (Cartesian)
#Used in key generation (not signing … ?)
sub get_y {
my (\$self) = @_;

return \$self->_get_x_or_y('y');
}

sub _get_x_or_y {
my (\$self, \$to_get) = @_;

if (!defined \$self->{'zinv'}) {
\$self->{'zinv'} = \$self->{'z'}->copy()->bmodinv(\$self->{'curve'}{'q'});
}

return \$self->{'curve'}->from_bigint(
\$self->{\$to_get}->to_bigint()->copy()->bmul(\$self->{'zinv'})->bmod(\$self->{'curve'}{'q'})
);
}

sub negate {
my (\$self) = @_;

my @args = @{\$self}{qw( curve x y z )};
\$args[2] = \$args[2]->negate();

return (ref \$self)->new(@args);
}

sub twice {
my (\$self) = @_;

return \$self if \$self->is_infinity();

#if (\$self->{'y'}->to_bigint()->signum() == 0) {
#    return \$self->{'curve'}->get_infinity();
#}

my \$x1 = \$self->{'x'}->to_bigint();
my \$y1 = \$self->{'y'}->to_bigint();

my \$y1z1 = \$y1->copy()->bmul(\$self->{'z'});

my \$y1sqz1 = \$y1z1->copy()->bmul(\$y1)->bmod(\$self->{'curve'}{'q'});

my \$a = \$self->{'curve'}{'a'};

# w = 3 * x1^2 + a * z1^2
#var w = x1.square().multiply(THREE);
my \$w = \$x1->copy()->bpow(\$bi2)->bmul(\$bi3);

if (!\$a->is_zero()) {
#\$w += (\$self->{'z'} ** 2) * \$a;
}

\$w->bmod(\$self->{'curve'}{'q'});

# x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
#var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);

my \$x3 = \$w->copy()->bmuladd( \$w, \$y1sqz1->copy()->bmul(\$x1)->blsft(\$bi3)->bneg() )->bmul(\$bi2)->bmul(\$y1z1);
#my \$x3 = 2 * \$y1z1 * ((\$w ** 2) - (\$x1 << 3) * \$y1sqz1);
#my \$x3 = (\$w ** 2) - ((\$x1 << 3) * \$y1sqz1);
#\$x3 = \$x3 << 1;
#\$x3 *= \$y1z1;

# y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
#var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
#my \$y3 = 4 * \$y1sqz1 * (3 * \$w * \$x1 - 2 * \$y1sqz1) - (\$w ** 3);

my \$y3 = \$y1sqz1->copy()->blsft(\$bi2);

#We don’t need y1sqz1 anymore

#Don’t need \$w anymore
\$w->bpow(\$bi3)->bneg(),
);

#// z3 = 8 * (y1 * z1)^3
#var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
#my \$z3 = (\$y1z1 ** 3) << 3;
my \$z3 = \$y1z1->bpow(\$bi3)->blsft(\$bi3);  #don’t need y1z1 anymore

#In original JS logic
\$_->bmod(\$self->{'curve'}{'q'}) for (\$x3, \$y3, \$z3);

#return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
return (ref \$self)->new(
\$self->{'curve'},
\$self->{'curve'}->from_bigint(\$x3),
\$self->{'curve'}->from_bigint(\$y3),
\$z3,
);
}

#XXX clear
sub dump {
my (\$self, \$label) = @_;

\$label = q<> if !defined \$label;

printf "\$label.x: %s\n", \$self->{'x'}->to_bigint()->as_hex();
printf "\$label.y: %s\n", \$self->{'y'}->to_bigint()->as_hex();
printf "\$label.z: %s\n", \$self->{'z'}->as_hex();
}

sub multiply {
my (\$self, \$k) = @_;

if (\$self->is_infinity()) {
return \$self;
}

# “Montgomery ladder” algorithm taken from Wikipedia:
#
# R0 ← 0
# R1 ← P
# for i from m downto 0 do
#     if di = 0 then
#         R0 ← point_double(R0)
#     else
#         R1 ← point_double(R1)
# return R0
#
# This thwarts the timing attacks that can recover private keys
# by running the standard “double-and-add” algorithm over and over
# and analyzing response times.

my \$r0 = ref(\$self)->new_infinity();
my \$r1 = \$self;

for my \$i ( reverse( 0 .. (\$k->bit_length() - 1) ) ) {
if (\$k->test_bit(\$i)) {
\$r1 = \$r1->twice();
}
else {
\$r0 = \$r0->twice();
}
}

return \$r0;
}

#\$b isa ECPoint
my (\$self, \$b) = @_;
#\$b->dump('\$b');

#if(this.isInfinity()) return b;
#if(b.isInfinity()) return this;

return \$b if \$self->is_infinity();
return \$self if \$b->is_infinity();

#// u = Y2 * Z1 - Y1 * Z2
#var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
\$self->{'z'},
\$self->{'y'}->to_bigint()->copy()->bneg()->bmul(\$b->{'z'}),
);
# \$b->{'z'};

#// v = X2 * Z1 - X1 * Z2
#var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
\$self->{'z'},
\$self->{'x'}->to_bigint()->copy()->bneg()->bmul(\$b->{'z'}),
);

\$_->bmod(\$self->{'curve'}{'q'}) for (\$u, \$v);
#print "u: " . \$u->as_hex() . \$/;
#print "v: " . \$v->as_hex() . \$/;
#if(BigInteger.ZERO.equals(v)) {
#    if(BigInteger.ZERO.equals(u)) {
#        return this.twice(); // this == b, so double
#    }
#return this.curve.getInfinity(); // this = -b, so infinity
#}
if (\$v->is_zero()) {
if (\$u->is_zero()) {
return \$self->twice();
}

return \$self->{'curve'}->get_infinity();
}

#var THREE = new BigInteger("3");
#var x1 = this.x.toBigInteger();
#var y1 = this.y.toBigInteger();
#var x2 = b.x.toBigInteger();
#var y2 = b.y.toBigInteger();
my (\$x1, \$y1, \$z1) = @{\$self}{ qw( x y z ) };
my (\$x2, \$y2, \$z2) = @{\$b}{ qw( x y z ) };

\$_ = \$_->to_bigint() for (\$x1, \$y1, \$x2, \$y2);

#var v2 = v.square();
#var v3 = v2.multiply(v);
#var x1v2 = x1.multiply(v2);
#var zu2 = u.square().multiply(this.z);

my \$v2 = \$v->copy()->bmul(\$v);
my \$v3 = \$v->copy()->bmul(\$v2);

my \$x1v2 = \$x1->copy()->bmul(\$v2);
my \$zu2 = \$u->copy()->bmul(\$u)->bmul(\$self->{'z'});
#use Data::Dumper;
#print Dumper( map { \$_->as_hex() } \$u, \$v, \$x1, \$y1, \$z1, \$x2, \$y2, \$z2, \$v2, \$v3, \$x1v2, \$zu2 );

#// x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
#var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
#my \$x3 = \$v * (\$z2 * (\$z1 * (\$u ** 2) - 2 * \$x1 * (\$v ** 2)) - (\$v ** 3));
my \$x3 = \$u->copy()->bmul(\$u);
\$x3->bmul(\$v);

#// y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
#my \$y3 = \$z2 * (3 * \$x1 * \$u * \$v2 - \$y1 * \$v3 - \$z1 * (\$u ** 3)) + \$u * \$v3;
my \$y3 = \$u->copy()->bmul(\$bi3)->bmul(\$x1);
\$y3->bmuladd(\$v2, \$y1->copy()->bmul(\$v3)->bneg());      #no more y1 after this
\$y3->bsub( \$u->copy()->bpow(\$bi3)->bmul(\$z1) );

\$y3->bmuladd( \$z2, \$u->bmul(\$v3) );             #we don’t need \$u anymore

#// z3 = v^3 * z1 * z2
#var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
my \$z3 = \$v3->bmul(\$z1)->bmul(\$z2);

\$_->bmod(\$self->{'curve'}{'q'}) for (\$x3, \$y3, \$z3);

return (ref \$self)->new(
\$self->{'curve'},
\$self->{'curve'}->from_bigint(\$x3),
\$self->{'curve'}->from_bigint(\$y3),
\$z3,
);
}

1;
``````