1package Crypt::Perl::ECDSA::EncodedPoint;
2
3use strict;
4use warnings;
5
6use Try::Tiny;
7
8use Crypt::Perl::ECDSA::Utils ();
9use Crypt::Perl::X ();
10
11#input can be a string or BigInt,
12#in any of “hybrid”, “uncompressed”, or “compressed” formats
13sub new {
14    my ($class, $input) = @_;
15
16    my $bin;
17
18    my $input_is_obj;
19    if ( try { $input->isa('Crypt::Perl::BigInt') } ) {
20        $bin = $input->as_bytes();
21        $input_is_obj = 1;
22    }
23    else {
24        $input =~ s<\A\0+><>;
25        $bin = $input;
26    }
27
28    my $first_octet = ord substr( $bin, 0, 1 );
29
30    my $self = bless {}, $class;
31
32    #Accommodate “hybrid” points
33    if ($first_octet == 6 || $first_octet == 7) {
34        $self->{'_bin'} = "\x04" . substr( $bin, 1 );
35    }
36    elsif ($first_octet == 4) {
37        $self->{'_bin'} = $bin;
38    }
39    elsif ($first_octet == 2 || $first_octet == 3) {
40        $self->{'_compressed_bin'} = $bin;
41    }
42    else {
43        die Crypt::Perl::X::Create('Generic', sprintf "Invalid leading octet in ECDSA point: %v02x", $bin);
44    }
45
46    return $self;
47}
48
49#returns a string
50sub get_compressed {
51    my ($self) = @_;
52
53    return $self->{'_compressed_bin'} ||= do {
54        Crypt::Perl::ECDSA::Utils::compress_point( $self->{'_bin'} );
55    };
56}
57
58#returns a string
59sub get_uncompressed {
60    my ($self, $curve_hr) = @_;
61
62    die "Need curve! (p, a, b)" if !$curve_hr;
63
64    return $self->{'_bin'} ||= do {
65        die "Need compressed bin!" if !$self->{'_compressed_bin'};
66
67        Crypt::Perl::ECDSA::Utils::decompress_point(
68            $self->{'_compressed_bin'},
69            @{$curve_hr}{ qw( p a b ) },
70        );
71    };
72}
73
74#If there’s ever a demand for “hybrid”:
75#0x06 and 0x07 take the place of the uncompressed leading 0x04,
76#analogous to 0x02 and 0x03 in the compressed form.
77
781;
79