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 1     1   6 use strict;
  1         2  
  1         36  
3 1     1   5 use warnings;
  1         2  
  1         35  
4 1     1   4 use Carp qw/carp croak confess/;
  1         2  
  1         82  
5              
6             BEGIN {
7 1     1   3 $Math::Prime::Util::ECProjectivePoint::AUTHORITY = 'cpan:DANAJ';
8 1         42 $Math::Prime::Util::ECProjectivePoint::VERSION = '0.68';
9             }
10              
11             BEGIN {
12 1 50   1   929 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 9     9 1 33 my ($class, $c, $n, $x, $z) = @_;
21 9 50       30 $c = Math::BigInt->new("$c") unless ref($c) eq 'Math::BigInt';
22 9 100       30 $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
23 9 100       62 $x = Math::BigInt->new("$x") unless ref($x) eq 'Math::BigInt';
24 9 100       58 $z = Math::BigInt->new("$z") unless ref($z) eq 'Math::BigInt';
25              
26 9 50       55 croak "n must be >= 2" unless $n >= 2;
27 9         858 $c->bmod($n);
28              
29 9         861 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 9         5180 bless $self, $class;
39 9         34 return $self;
40             }
41              
42             sub _addx {
43 196     196   497 my ($x1, $x2, $xin, $n) = @_;
44              
45 196         524 my $u = ($x2 - 1) * ($x1 + 1);
46 196         81812 my $v = ($x2 + 1) * ($x1 - 1);
47              
48 196         78663 my $upv2 = ($u + $v) ** 2;
49 196         72899 my $umv2 = ($u - $v) ** 2;
50              
51 196         70565 return ( $upv2 % $n, ($umv2*$xin) % $n );
52             }
53              
54             sub _add3 {
55 104     104   215 my ($x1, $z1, $x2, $z2, $xin, $zin, $n) = @_;
56              
57 104         296 my $u = ($x2 - $z2) * ($x1 + $z1);
58 104         32575 my $v = ($x2 + $z2) * ($x1 - $z1);
59              
60 104         31804 my $upv2 = $u + $v; $upv2->bmul($upv2);
  104         9453  
61 104         17346 my $umv2 = $u - $v; $umv2->bmul($umv2);
  104         11337  
62              
63 104         17133 $upv2->bmul($zin)->bmod($n);
64 104         57348 $umv2->bmul($xin)->bmod($n);
65 104         58167 return ($upv2, $umv2);
66             }
67              
68             sub _double {
69 243     243   568 my ($x, $z, $n, $d) = @_;
70              
71 243         657 my $u = $x + $z; $u->bmul($u);
  243         22100  
72 243         24340 my $v = $x - $z; $v->bmul($v);
  243         31478  
73              
74 243         23455 my $w = $u - $v;
75 243         31096 my $t = $d * $w + $v;
76              
77 243         44343 $u->bmul($v)->bmod($n);
78 243         100139 $w->bmul($t)->bmod($n);
79 243         99824 return ($u, $w);
80             }
81              
82             sub mul {
83 28     28 1 67 my ($self, $k) = @_;
84 28         54 my $x = $self->{'x'};
85 28         48 my $z = $self->{'z'};
86 28         50 my $n = $self->{'n'};
87 28         44 my $d = $self->{'d'};
88              
89 28         54 my ($x1, $x2, $z1, $z2);
90              
91 28         50 my $r = --$k;
92 28         51 my $l = -1;
93 28         67 while ($r != 1) { $r >>= 1; $l++ }
  102         124  
  102         166  
94 28 100       78 if ($k & (1 << $l)) {
95 10         24 ($x2, $z2) = _double($x, $z, $n, $d);
96 10         31 ($x1, $z1) = _add3($x2, $z2, $x, $z, $x, $z, $n);
97 10         30 ($x2, $z2) = _double($x2, $z2, $n, $d);
98             } else {
99 18         44 ($x1, $z1) = _double($x, $z, $n, $d);
100 18         51 ($x2, $z2) = _add3($x, $z, $x1, $z1, $x, $z, $n);
101             }
102 28         62 $l--;
103 28         76 while ($l >= 1) {
104 48 100       125 if ($k & (1 << $l)) {
105 21         55 ($x1, $z1) = _add3($x1, $z1, $x2, $z2, $x, $z, $n);
106 21         74 ($x2, $z2) = _double($x2, $z2, $n, $d);
107             } else {
108 27         62 ($x2, $z2) = _add3($x2, $z2, $x1, $z1, $x, $z, $n);
109 27         95 ($x1, $z1) = _double($x1, $z1, $n, $d);
110             }
111 48         184 $l--;
112             }
113 28 50       75 if ($k & 1) {
114 0         0 ($x, $z) = _double($x2, $z2, $n, $d);
115             } else {
116 28         61 ($x, $z) = _add3($x2, $z2, $x1, $z1, $x, $z, $n);
117             }
118              
119 28         77 $self->{'x'} = $x;
120 28         71 $self->{'z'} = $z;
121 28         133 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 16     16 1 33 my ($self) = @_;
141 16         52 ($self->{'x'}, $self->{'z'}) = _double($self->{'x'}, $self->{'z'}, $self->{'n'}, $self->{'d'});
142 16         72 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 4     4 1 12 my ($self) = @_;
160 4         11 my $n = $self->{'n'};
161 4         8 my $z = $self->{'z'};
162             #my ($f, $u, undef) = _extended_gcd( $z, $n );
163 4         11 my $f = Math::BigInt::bgcd( $z, $n );
164 4         8853 my $u = $z->copy->bmodinv($n);
165 4         13095 $self->{'x'} = ( $self->{'x'} * $u ) % $n;
166 4         1221 $self->{'z'} = $n-$n+1;
167 4         930 $self->{'f'} = ($f * $self->{'f'}) % $n;
168 4         622 return $self;
169             }
170              
171 0     0 1 0 sub c { return shift->{'c'}; }
172 4     4 1 11 sub d { return shift->{'d'}; }
173 0     0 1 0 sub n { return shift->{'n'}; }
174 32     32 1 102 sub x { return shift->{'x'}; }
175 0     0 1 0 sub z { return shift->{'z'}; }
176 4     4 1 12 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 4     4 1 7 my $self = shift;
185             return Math::Prime::Util::ECProjectivePoint->new(
186 4         17 $self->{'c'}, $self->{'n'}, $self->{'x'}, $self->{'z'});
187             }
188              
189             1;
190              
191             __END__