our
$VERSION
=
'0.060'
;
use
Carp
qw( carp croak )
;
our
$WARN_IF_NEW_POINT_INVALID
= 0;
sub
new {
my
(
$class
,
%args
) =
@_
;
my
$self
= {};
bless
$self
,
$class
;
$self
->{curve} =
$args
{curve}
or croak
"Must have curve for a point on curve"
;
if
(
$args
{octet} ) {
$self
->from_octet(
$args
{octet} );
}
else
{
$self
->{X} = bint(
$args
{X} );
$self
->{Y} = bint(
$args
{Y} );
}
$self
->{order} =
$args
{order} ? bint(
$args
{order} ) :
$self
->{curve}->{order};
$self
->{is_infinity} = (
$args
{is_infinity} ? 1 : 0 );
carp
"New Point ( $self->{X} , $self->{Y} ) is not on curve"
if
$WARN_IF_NEW_POINT_INVALID
and
!
$self
->{curve}->is_on_curve(
$self
->{X},
$self
->{Y} );
bless
$self
,
$class
;
return
$self
;
}
sub
X {
my
(
$self
,
$new_X
) =
@_
;
$self
->{X} =
$new_X
if
$new_X
;
return
$self
->{X};
}
sub
Y {
my
(
$self
,
$new_Y
) =
@_
;
$self
->{Y} =
$new_Y
if
$new_Y
;
return
$self
->{Y};
}
sub
curve {
my
(
$self
,
$new_curve
) =
@_
;
$self
->{curve} =
$new_curve
if
$new_curve
;
return
$self
->{curve};
}
sub
order {
my
(
$self
,
$new_order
) =
@_
;
$self
->{order} =
$new_order
if
$new_order
;
return
$self
->{order};
}
sub
deep_copy {
my
(
$self
) =
@_
;
my
$point
= Crypt::ECDSA::Point->new(
X
=>
$self
->{X},
Y
=>
$self
->{Y},
order
=>
$self
->{order},
curve
=>
$self
->{curve},
is_infinity
=>
$self
->{is_infinity},
);
return
$point
;
}
sub
is_point_at_infinity() {
my
$self
=
shift
;
return
$self
->{is_infinity};
}
sub
add {
my
(
$p1
,
$p2
) =
@_
;
return
$p1
if
$p2
->{is_infinity};
return
$p2
if
$p1
->{is_infinity};
croak(
"Cannot add points on two different curves"
)
if
$p1
->{curve} !=
$p2
->{curve};
return
$p1
->{curve}
->add_on_curve(
$p1
->{X},
$p1
->{Y},
$p2
->{X},
$p2
->{Y},
$p1
->{order} );
}
sub
inverse {
my
(
$self
) =
@_
;
return
$self
->{curve}
->inverse_on_curve(
$self
->{X},
$self
->{Y},
$self
->{order} );
}
sub
double {
my
(
$self
) =
@_
;
return
$self
->{curve}
->double_on_curve(
$self
->{X},
$self
->{Y},
$self
->{order} );
}
sub
multiply {
my
(
$self
,
$scalar
) =
@_
;
$scalar
= bint(
$scalar
);
return
$self
->{curve}
->multiply_on_curve(
$self
->{X},
$self
->{Y},
$scalar
,
$self
->{order} );
}
sub
is_equal_to {
my
(
$p1
,
$p2
) =
@_
;
return
1
unless
$p1
->{X} or
$p1
->{Y} or
$p2
->{X} or
$p2
->{Y};
if
(
$p1
->{is_infinity} ) {
return
(
$p2
->{is_infinity} ) ? 1 : 0;
}
if
(
$p2
->{is_infinity} ) {
return
(
$p1
->{is_infinity} ) ? 1 : 0;
}
return
(
$p1
->{X} ==
$p2
->{X} and
$p1
->{Y} ==
$p2
->{Y} ) ? 1 : 0;
}
sub
is_on_curve {
my
$p
=
shift
;
return
$p
->curve->is_on_curve(
$p
->X,
$p
->Y );
}
sub
to_octet {
my
(
$self
,
$compressed
) =
@_
;
return
"\x00"
if
$self
->{is_infinity};
return
$self
->curve->to_octet(
$self
->X,
$self
->Y,
$compressed
);
}
sub
from_octet {
my
(
$self
,
$octet
) =
@_
;
if
(
$octet
eq
"\x00"
) {
$self
->{X} = 0;
$self
->{Y} = 0;
$self
->{is_infinity} = 1;
return
$self
;
}
my
(
$x
,
$y
) =
$self
->{curve}->from_octet(
$octet
);
unless
(
$x
and
$y
) {
carp(
"Bad octet for point"
);
return
;
}
$self
->{X} =
$x
;
$self
->{Y} =
$y
;
$self
->{order} =
$self
->{curve}->{order}
unless
$self
->{order};
return
$self
;
}
'='
=>
sub
{
$_
[0]->deep_copy(
$_
[1] ) },
'+'
=>
sub
{
$_
[0]->add(
$_
[1] ) },
'-'
=>
sub
{
$_
[0]->add(
$_
[1]->inverse ) },
'*'
=>
sub
{
$_
[0]->multiply(
$_
[1] ) },
'=='
=>
sub
{
$_
[0]->is_equal_to(
$_
[1] ) },
'!='
=>
sub
{ !
$_
[0]->is_equal_to(
$_
[1] ) };
1;