our
$VERSION
=
'0.067'
;
no
warnings;
our
$standard_curve
=
$Crypt::ECDSA::Curve::named_curve
;
sub
new {
my
(
$class
,
%args
) =
@_
;
my
$self
= {};
bless
$self
,
$class
;
my
$x
= bint(
$args
{X} || 0 );
my
$y
= bint(
$args
{Y} || 0 );
if
(
$args
{PEM} ) {
my
$pem
= Crypt::ECDSA::PEM->new(
filename
=>
$args
{PEM},
password
=>
$args
{password} );
if
(
exists
$pem
->{private_pem_tree}->{standard} ) {
$args
{standard} =
$pem
->{private_pem_tree}->{standard};
$args
{Q} =
$pem
->{private_pem_tree}->{Q};
$args
{d} =
$pem
->{private_pem_tree}->{d};
$args
{order} =
$pem
->{private_pem_tree}->{order};
}
}
if
(
$args
{standard} ) {
$self
->{standard} =
$args
{standard};
if
(
$standard_curve
->{
$self
->{standard} } ) {
my
$named_curve
=
$Crypt::ECDSA::Curve::named_curve
;
my
$alg
=
$named_curve
->{
$self
->{standard} }->{algorithm};
if
(
$alg
eq
'Prime'
) {
$self
->{curve} =
Crypt::ECDSA::Curve::Prime->new(
standard
=>
$self
->{standard} );
}
elsif
(
$alg
eq
'Koblitz'
) {
$self
->{curve} =
Crypt::ECDSA::Curve::Koblitz->new(
standard
=>
$self
->{standard} );
}
$x
=
$self
->{curve}->{G_x}
if
$self
->{curve}->{G_x};
$y
=
$self
->{curve}->{G_y}
if
$self
->{curve}->{G_y};
}
else
{
croak(
"ECDSA->new: standard curve type "
.
$self
->{standard}
.
"not found"
);
}
}
else
{
if
(
$args
{curve} ) {
$self
->{curve} =
$args
{curve};
}
else
{
croak(
"A curve must be specified for ECDSA signature : specified was "
,
values
%args
);
}
}
my
$order
=
$args
{order} ||
$self
->{curve}->{point_order};
croak(
"Point G(x,y) must have positive order"
)
unless
$order
and
$order
> 0;
croak(
"point (G_x "
.
$x
->as_hex
.
", G_y "
.
$y
->as_hex
.
") not on the curve, cannot create ECDSA"
)
unless
$self
->{curve}->is_on_curve(
$x
,
$y
);
$self
->{G} = Crypt::ECDSA::Point->new(
X
=>
$x
,
Y
=>
$y
,
curve
=>
$self
->{curve},
order
=>
$order
);
$self
->{d} = bint(
$args
{d} )
if
defined
$args
{d};
$self
->new_secret_value()
unless
defined
$self
->{d} and
$self
->{d} > 0;
$self
->{Q} =
$args
{Q}
if
defined
$args
{Q};
$self
->{Q} =
$self
->{G} *
$self
->{d}
unless
defined
$self
->{Q};
$self
->{Q}->{curve} =
$self
->{G}->{curve};
return
$self
;
}
sub
curve {
return
shift
->{curve} }
sub
Q {
return
shift
->{Q} }
sub
Qx {
return
shift
->{Q}->{X} }
sub
Qy {
return
shift
->{Q}->{Y} }
sub
order {
return
shift
->{G}->{order} }
sub
secret {
return
shift
->{d} }
sub
G {
return
shift
->{G} }
sub
set_public_Q {
my
(
$self
,
$pub_x
,
$pub_y
) =
@_
;
my
$new_Q
= Crypt::ECDSA::Point->new(
X
=>
$pub_x
,
Y
=>
$pub_y
,
curve
=>
$self
->curve,
order
=>
$self
->order,
is_infinity
=> 0,
);
$self
->{Q} =
$new_Q
;
$self
->{d} =
undef
;
return
$new_Q
;
}
sub
new_key_values {
my
(
$self
) =
@_
;
$self
->new_secret_value();
$self
->{Q} =
$self
->{G} *
$self
->{d};
return
( bint(
$self
->{d} ), bint(
$self
->{Q}->{X} ),
bint(
$self
->{Q}->{Y} ) );
}
sub
new_secret_value {
my
(
$self
) =
@_
;
my
$n
=
$self
->{G}->{order};
my
$len
=
length
(
$n
->as_hex ) - 2;
$self
->{d} =
( random_bits( (
$len
+ 8) * 16 ) % (
$n
- 1 ) ) + 1;
return
$self
->{d};
}
sub
verify_public_key {
my
(
$self
,
$Qx
,
$Qy
) =
@_
;
my
$q
=
$self
->curve->
q;
return if $Qx <
0 or
$Qx
>=
$q
or
$Qy
< 0 or
$Qy
>=
$q
;
return
unless
$self
->curve->is_on_curve(
$Qx
,
$Qy
);
my
$Q
= Crypt::ECDSA::Point->new(
X
=>
$Qx
,
Y
=>
$Qy
,
curve
=>
$self
->curve,
order
=>
$self
->order,
is_infinity
=> 0,
);
my
$r
=
$self
->curve->{point_order};
return
unless
$r
;
my
$product
=
$Q
*
$r
;
return
unless
$product
->is_point_at_infinity;
return
1;
}
sub
read_PEM {
my
(
$self
,
%args
) =
@_
;
if
(
$args
{filename} and
$args
{private}) {
my
$pem
= Crypt::ECDSA::PEM->new(
filename
=>
$args
{filename},
password
=>
$args
{password} );
$self
->{Q} =
$pem
->{private_pem_tree}->{Q};
$self
->{d} =
$pem
->{private_pem_tree}->{d};
$self
->{order} =
$pem
->{private_pem_tree}->{order};
$self
->{curve} =
$pem
->{private_pem_tree}->{curve};
$self
->{G} = Crypt::ECDSA::Point->new(
X
=>
$self
->{curve}->{Gx},
Y
=>
$self
->{curve}->{Gy},
curve
=>
$self
->{curve},
order
=>
$self
->{curve}->{order},
);
}
return
$self
;
}
sub
write_PEM {
my
(
$self
,
%args
) =
@_
;
if
(
$args
{filename} and
$args
{private} ) {
my
$pem
= Crypt::ECDSA::PEM->new();
my
%pem_args
;
$pem_args
{key} =
$self
;
$pem_args
{filename} =
$args
{filename};
$pem_args
{private} = 1;
$pem_args
{password} =
$args
{password}
if
$args
{password};
return
$pem
->write_PEM(
%pem_args
);
}
return
;
}
1;