File Coverage

blib/lib/Math/Prime/Util/ECAffinePoint.pm
Criterion Covered Total %
statement 74 114 64.9
branch 19 46 41.3
condition 7 25 28.0
subroutine 10 19 52.6
pod 10 10 100.0
total 120 214 56.0


line stmt bran cond sub pod time code
1             package Math::Prime::Util::ECAffinePoint;
2 1     1   9 use strict;
  1         4  
  1         39  
3 1     1   5 use warnings;
  1         2  
  1         46  
4 1     1   7 use Carp qw/carp croak confess/;
  1         2  
  1         114  
5              
6             BEGIN {
7 1     1   5 $Math::Prime::Util::ECAffinePoint::AUTHORITY = 'cpan:DANAJ';
8 1         65 $Math::Prime::Util::ECAffinePoint::VERSION = '0.73';
9             }
10              
11             BEGIN {
12 1 50   1   1433 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 affine coordinates. Should be split into a point class.
18              
19             sub new {
20 9     9 1 40 my ($class, $a, $b, $n, $x, $y) = @_;
21 9 50       33 $a = Math::BigInt->new("$a") unless ref($a) eq 'Math::BigInt';
22 9 50       35 $b = Math::BigInt->new("$b") unless ref($b) eq 'Math::BigInt';
23 9 50       27 $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
24 9 50       26 $x = Math::BigInt->new("$x") unless ref($x) eq 'Math::BigInt';
25 9 50       32 $y = Math::BigInt->new("$y") unless ref($y) eq 'Math::BigInt';
26              
27 9 50       31 croak "n must be >= 2" unless $n >= 2;
28 9         1058 $a->bmod($n);
29 9         1067 $b->bmod($n);
30              
31 9         894 my $self = {
32             a => $a,
33             b => $b,
34             n => $n,
35             x => $x,
36             y => $y,
37             f => $n->copy->bone,
38             };
39              
40 9         935 bless $self, $class;
41 9         31 return $self;
42             }
43              
44             sub _add {
45 0     0   0 my ($self, $P1x, $P1y, $P2x, $P2y) = @_;
46 0         0 my $n = $self->{'n'};
47              
48 0 0       0 if ($P1x == $P2x) {
49 0         0 my $t = ($P1y + $P2y) % $n;
50 0 0       0 return (Math::BigInt->bzero,Math::BigInt->bone) if $t == 0;
51             }
52 0         0 my $deltax = ($P2x - $P1x) % $n;
53 0         0 $deltax->bmodinv($n);
54 0 0       0 return (Math::BigInt->bzero,Math::BigInt->bone) if $deltax eq "NaN";
55              
56 0         0 my $deltay = ($P2y - $P1y) % $n;
57 0         0 my $m = ($deltay * $deltax) % $n; # m = deltay / deltax
58              
59 0         0 my $x = ($m*$m - $P1x - $P2x) % $n;
60 0         0 my $y = ($m*($P1x - $x) - $P1y) % $n;
61 0         0 return ($x,$y);
62             }
63              
64             sub _double {
65 0     0   0 my ($self, $P1x, $P1y) = @_;
66 0         0 my $n = $self->{'n'};
67              
68 0         0 my $m = 2*$P1y;
69 0         0 $m->bmodinv($n);
70 0 0       0 return (Math::BigInt->bzero,Math::BigInt->bone) if $m eq "NaN";
71              
72 0         0 $m = ((3*$P1x*$P1x + $self->{'a'}) * $m) % $n;
73              
74 0         0 my $x = ($m*$m - 2*$P1x) % $n;
75 0         0 my $y = ($m*($P1x - $x) - $P1y) % $n;
76 0         0 return ($x,$y);
77             }
78              
79             sub _inplace_add {
80 147     147   382 my ($P1x, $P1y, $x, $y, $n) = @_;
81              
82 147 100       822 if ($P1x == $x) {
83 9         379 my $t = ($P1y + $y) % $n;
84 9 50       1825 if ($t == 0) {
85 9         1927 ($_[2],$_[3]) = (Math::BigInt->bzero,Math::BigInt->bone);
86 9         1161 return;
87             }
88             }
89 138         6028 my $deltax = ($x - $P1x) % $n;
90 138         36898 $deltax->bmodinv($n);
91 138 50       499310 if ($deltax eq 'NaN') {
92 0         0 ($_[2],$_[3]) = (Math::BigInt->bzero,Math::BigInt->bone);
93 0         0 return;
94             }
95 138         4239 my $deltay = ($y - $P1y) % $n;
96 138         37427 my $m = ($deltay * $deltax) % $n; # m = deltay / deltax
97              
98 138         48168 $_[2] = ($m*$m - $P1x - $x) % $n;
99 138         85342 $_[3] = ($m*($P1x - $_[2]) - $P1y) % $n;
100             }
101             sub _inplace_double {
102 331     331   777 my($x, $y, $a, $n) = @_;
103 331         978 my $m = $y+$y;
104 331         28837 $m->bmodinv($n);
105 331 50       1091259 if ($m eq 'NaN') {
106 0         0 ($_[0],$_[1]) = (Math::BigInt->bzero,Math::BigInt->bone);
107 0         0 return;
108             }
109 331         9605 $m->bmul($x->copy->bmul($x)->bmul(3)->badd($a))->bmod($n);
110              
111 331         233891 my $xin = $x->copy;
112 331         7314 $_[0] = ($m*$m - $x - $x) % $n;
113 331         200863 $_[1] = ($m*($xin - $_[0]) - $y) % $n;
114             }
115              
116             sub mul {
117 18     18 1 2035 my ($self, $k) = @_;
118 18         62 my $x = $self->{'x'};
119 18         67 my $y = $self->{'y'};
120 18         46 my $a = $self->{'a'};
121 18         35 my $n = $self->{'n'};
122 18         45 my $f = $self->{'f'};
123 18 50 33     132 if (ref($k) eq 'Math::BigInt' && $k < ''.~0) {
124 18 50 50     2590 if ($] >= 5.008 || ~0 == 4294967295) {
    0 0        
      0        
125 18         61 $k = int($k->bstr);
126             } elsif ($] < 5.008 && ~0 > 4294967295 && $k < 562949953421312) {
127 0         0 $k = unpack('Q',pack('Q',$k->bstr));
128             }
129             }
130              
131 18         385 my $Bx = $n->copy->bzero;
132 18         826 my $By = $n->copy->bone;
133 18         1553 my $v = 1;
134              
135 18         56 while ($k > 0) {
136 496 100       276354 if ( ($k % 2) != 0) {
137 165         365 $k--;
138 165         540 $f->bmul($Bx-$x)->bmod($n);
139 165 50 33     70097 if ($x->is_zero && $y->is_one) { }
    100 66        
140 18         716 elsif ($Bx->is_zero && $By->is_one) { ($Bx,$By) = ($x,$y); }
141 147         3841 else { _inplace_add($x,$y,$Bx,$By,$n); }
142             } else {
143 331         566 $k >>= 1;
144 331         932 $f->bmul(2*$y)->bmod($n);
145 331         155237 _inplace_double($x,$y,$a,$n);
146             }
147             }
148 18         3904 $f = Math::BigInt::bgcd($f, $n);
149 18         11147 $self->{'x'} = $Bx;
150 18         70 $self->{'y'} = $By;
151 18         68 $self->{'f'} = $f;
152 18         118 return $self;
153             }
154              
155             sub add {
156 0     0 1 0 my ($self, $other) = @_;
157 0 0       0 croak "add takes a EC point"
158             unless ref($other) eq 'Math::Prime::Util::ECAffinePoint';
159             croak "second point is not on the same curve"
160             unless $self->{'a'} == $other->{'a'} &&
161             $self->{'b'} == $other->{'b'} &&
162 0 0 0     0 $self->{'n'} == $other->{'n'};
      0        
163              
164             ($self->{'x'}, $self->{'y'}) = $self->_add($self->{'x'}, $self->{'y'},
165 0         0 $other->{'x'}, $other->{'y'});
166 0         0 return $self;
167             }
168              
169              
170 0     0 1 0 sub a { return shift->{'a'}; }
171 0     0 1 0 sub b { return shift->{'b'}; }
172 0     0 1 0 sub n { return shift->{'n'}; }
173 0     0 1 0 sub x { return shift->{'x'}; }
174 0     0 1 0 sub y { return shift->{'y'}; }
175 0     0 1 0 sub f { return shift->{'f'}; }
176              
177             sub is_infinity {
178 18     18 1 41 my $self = shift;
179 18   66     70 return ($self->{'x'}->is_zero() && $self->{'y'}->is_one());
180             }
181              
182             1;
183              
184             __END__