File Coverage

blib/lib/Math/Prime/Util/ECProjectivePoint.pm
Criterion Covered Total %
statement 95 108 87.9
branch 14 22 63.6
condition 0 6 0.0
subroutine 16 21 76.1
pod 13 13 100.0
total 138 170 81.1


line stmt bran cond sub pod time code
1             package Math::Prime::Util::ECProjectivePoint;
2 2     2   15 use strict;
  2         6  
  2         72  
3 2     2   12 use warnings;
  2         3  
  2         88  
4 2     2   12 use Carp qw/carp croak confess/;
  2         6  
  2         227  
5              
6             BEGIN {
7 2     2   8 $Math::Prime::Util::ECProjectivePoint::AUTHORITY = 'cpan:DANAJ';
8 2         112 $Math::Prime::Util::ECProjectivePoint::VERSION = '0.73';
9             }
10              
11             BEGIN {
12 2 50   2   2231 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }
  0         0  
  0         0  
13             unless defined $Math::BigInt::VERSION;
14             }
15              
16             # Pure perl (with Math::BigInt) manipulation of Elliptic Curves
17             # in projective coordinates.
18              
19             sub new {
20 46     46 1 218 my ($class, $c, $n, $x, $z) = @_;
21 46 50       209 $c = Math::BigInt->new("$c") unless ref($c) eq 'Math::BigInt';
22 46 100       199 $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
23 46 100       242 $x = Math::BigInt->new("$x") unless ref($x) eq 'Math::BigInt';
24 46 100       223 $z = Math::BigInt->new("$z") unless ref($z) eq 'Math::BigInt';
25              
26 46 50       194 croak "n must be >= 2" unless $n >= 2;
27 46         5470 $c->bmod($n);
28              
29 46         5444 my $self = {
30             c => $c,
31             d => ($c + 2) >> 2,
32             n => $n,
33             x => $x,
34             z => $z,
35             f => $n-$n+1,
36             };
37              
38 46         33991 bless $self, $class;
39 46         214 return $self;
40             }
41              
42             sub _addx {
43 1771     1771   5264 my ($x1, $x2, $xin, $n) = @_;
44              
45 1771         5113 my $u = ($x2 - 1) * ($x1 + 1);
46 1771         927218 my $v = ($x2 + 1) * ($x1 - 1);
47              
48 1771         897986 my $upv2 = ($u + $v) ** 2;
49 1771         1030902 my $umv2 = ($u - $v) ** 2;
50              
51 1771         988343 return ( $upv2 % $n, ($umv2*$xin) % $n );
52             }
53              
54             sub _add3 {
55 22725     22725   49993 my ($x1, $z1, $x2, $z2, $xin, $zin, $n) = @_;
56              
57 22725         62590 my $u = ($x2 - $z2) * ($x1 + $z1);
58 22725         8514008 my $v = ($x2 + $z2) * ($x1 - $z1);
59              
60 22725         8356010 my $upv2 = $u + $v; $upv2->bmul($upv2);
  22725         2356122  
61 22725         4786065 my $umv2 = $u - $v; $umv2->bmul($umv2);
  22725         2912180  
62              
63 22725         4789602 $upv2->bmul($zin)->bmod($n);
64 22725         15722905 $umv2->bmul($xin)->bmod($n);
65 22725         15784429 return ($upv2, $umv2);
66             }
67              
68             sub _double {
69 22288     22288   46936 my ($x, $z, $n, $d) = @_;
70              
71 22288         59564 my $u = $x + $z; $u->bmul($u);
  22288         1964521  
72 22288         3252209 my $v = $x - $z; $v->bmul($v);
  22288         3082370  
73              
74 22288         3201676 my $w = $u - $v;
75 22288         3252794 my $t = $d * $w + $v;
76              
77 22288         5677791 $u->bmul($v)->bmod($n);
78 22288         12917216 $w->bmul($t)->bmod($n);
79 22288         14992099 return ($u, $w);
80             }
81              
82             sub mul {
83 2857     2857 1 7389 my ($self, $k) = @_;
84 2857         6869 my $x = $self->{'x'};
85 2857         5883 my $z = $self->{'z'};
86 2857         6333 my $n = $self->{'n'};
87 2857         5969 my $d = $self->{'d'};
88              
89 2857         5994 my ($x1, $x2, $z1, $z2);
90              
91 2857         5259 my $r = --$k;
92 2857         6505 my $l = -1;
93 2857         9100 while ($r != 1) { $r >>= 1; $l++ }
  22722         31017  
  22722         38943  
94 2857 100       12557 if ($k & (1 << $l)) {
95 1317         3601 ($x2, $z2) = _double($x, $z, $n, $d);
96 1317         5664 ($x1, $z1) = _add3($x2, $z2, $x, $z, $x, $z, $n);
97 1317         5779 ($x2, $z2) = _double($x2, $z2, $n, $d);
98             } else {
99 1540         4177 ($x1, $z1) = _double($x, $z, $n, $d);
100 1540         5929 ($x2, $z2) = _add3($x, $z, $x1, $z1, $x, $z, $n);
101             }
102 2857         9248 $l--;
103 2857         8083 while ($l >= 1) {
104 17011 100       46575 if ($k & (1 << $l)) {
105 8313         19743 ($x1, $z1) = _add3($x1, $z1, $x2, $z2, $x, $z, $n);
106 8313         33002 ($x2, $z2) = _double($x2, $z2, $n, $d);
107             } else {
108 8698         22785 ($x2, $z2) = _add3($x2, $z2, $x1, $z1, $x, $z, $n);
109 8698         34311 ($x1, $z1) = _double($x1, $z1, $n, $d);
110             }
111 17011         73655 $l--;
112             }
113 2857 50       12385 if ($k & 1) {
114 0         0 ($x, $z) = _double($x2, $z2, $n, $d);
115             } else {
116 2857         10262 ($x, $z) = _add3($x2, $z2, $x1, $z1, $x, $z, $n);
117             }
118              
119 2857         11682 $self->{'x'} = $x;
120 2857         10212 $self->{'z'} = $z;
121 2857         18872 return $self;
122             }
123              
124             sub add {
125 0     0 1 0 my ($self, $other) = @_;
126 0 0       0 croak "add takes a EC point"
127             unless ref($other) eq 'Math::Prime::Util::ECProjectivePoint';
128             croak "second point is not on the same curve"
129             unless $self->{'c'} == $other->{'c'} &&
130 0 0 0     0 $self->{'n'} == $other->{'n'};
131              
132             ($self->{'x'}, $self->{'z'}) = _add3($self->{'x'}, $self->{'z'},
133             $other->{'x'}, $other->{'z'},
134             $self->{'x'}, $self->{'z'},
135 0         0 $self->{'n'});
136 0         0 return $self;
137             }
138              
139             sub double {
140 174     174 1 375 my ($self) = @_;
141 174         524 ($self->{'x'}, $self->{'z'}) = _double($self->{'x'}, $self->{'z'}, $self->{'n'}, $self->{'d'});
142 174         896 return $self;
143             }
144              
145             #sub _extended_gcd {
146             # my ($a, $b) = @_;
147             # my $zero = $a-$a;
148             # my ($x, $lastx, $y, $lasty) = ($zero, $zero+1, $zero+1, $zero);
149             # while ($b != 0) {
150             # my $q = int($a/$b);
151             # ($a, $b) = ($b, $a % $b);
152             # ($x, $lastx) = ($lastx - $q*$x, $x);
153             # ($y, $lasty) = ($lasty - $q*$y, $y);
154             # }
155             # return ($a, $lastx, $lasty);
156             #}
157              
158             sub normalize {
159 22     22 1 88 my ($self) = @_;
160 22         68 my $n = $self->{'n'};
161 22         82 my $z = $self->{'z'};
162             #my ($f, $u, undef) = _extended_gcd( $z, $n );
163 22         81 my $f = Math::BigInt::bgcd( $z, $n );
164 22         69714 my $u = $z->copy->bmodinv($n);
165 22         102435 $self->{'x'} = ( $self->{'x'} * $u ) % $n;
166 22         9639 $self->{'z'} = $n-$n+1;
167 22         6116 $self->{'f'} = ($f * $self->{'f'}) % $n;
168 22         4365 return $self;
169             }
170              
171 0     0 1 0 sub c { return shift->{'c'}; }
172 22     22 1 78 sub d { return shift->{'d'}; }
173 0     0 1 0 sub n { return shift->{'n'}; }
174 2879     2879 1 11369 sub x { return shift->{'x'}; }
175 0     0 1 0 sub z { return shift->{'z'}; }
176 22     22 1 94 sub f { return shift->{'f'}; }
177              
178             sub is_infinity {
179 0     0 1 0 my $self = shift;
180 0   0     0 return ($self->{'x'}->is_zero() && $self->{'z'}->is_one());
181             }
182              
183             sub copy {
184 22     22 1 74 my $self = shift;
185             return Math::Prime::Util::ECProjectivePoint->new(
186 22         144 $self->{'c'}, $self->{'n'}, $self->{'x'}, $self->{'z'});
187             }
188              
189             1;
190              
191             __END__