File Coverage

blib/lib/Crypt/Perl/ECDSA/EC/Point.pm
Criterion Covered Total %
statement 84 93 90.3
branch 13 22 59.0
condition 11 17 64.7
subroutine 13 14 92.8
pod 0 9 0.0
total 121 155 78.0


line stmt bran cond sub pod time code
1             package Crypt::Perl::ECDSA::EC::Point;
2              
3 9     9   67 use strict;
  9         22  
  9         277  
4 9     9   55 use warnings;
  9         26  
  9         220  
5              
6             #----------------------------------------------------------------------
7             # NOTE TO SELF: This module’s internal coordinates are
8             # homogeneous/projective coordinates, not Cartesian.
9             #----------------------------------------------------------------------
10              
11 9     9   58 use Crypt::Perl::BigInt ();
  9         21  
  9         13921  
12              
13             my ($bi1, $bi2, $bi3);
14              
15             END {
16 9     9   98373 undef $bi1, $bi2, $bi3;
17             }
18              
19             sub new_infinity {
20 1790     1790 0 6416 my ($class) = @_;
21              
22 1790         6910 return $class->new( undef, undef );
23             }
24              
25             #$curve is ECCurve
26             #$x and $y are “ECFieldElement”
27             #$z isa bigint (?)
28             sub new {
29 743377     743377 0 1541065 my ($class, $curve, $x, $y, $z) = @_;
30              
31 743377   66     2171869 $bi1 ||= Crypt::Perl::BigInt->new(1);
32 743377   66     14472074 $bi2 ||= Crypt::Perl::BigInt->new(2);
33 743377   66     11872314 $bi3 ||= Crypt::Perl::BigInt->new(3);
34              
35 743377   66     11763722 my $self = {
36             curve => $curve,
37             x => $x,
38             y => $y,
39              
40             # Generally z won’t be given since we expect
41             # Cartesian coordinates as input. But accepting
42             # z allows this constructor to receive Jacobi
43             # coordinates as well.
44             z => $z || $bi1->copy(),
45              
46             zinv => undef,
47             };
48              
49 743377         21131154 return bless $self, $class;
50             }
51              
52             sub is_infinity {
53 1112610     1112610 0 1742610 my ($self) = @_;
54              
55 1112610 50 66     2454582 return 1 if !defined $self->{'x'} && !defined $self->{'y'};
56              
57 1111179   50     2258810 return( ($self->{'z'}->is_zero() && !$self->{'y'}->to_bigint()->is_zero()) || 0 );
58             }
59              
60             #returns ECFieldElement (Cartesian)
61             sub get_x {
62 966     966 0 4068 my ($self) = @_;
63              
64 966         7343 return $self->_get_x_or_y('x');
65             }
66              
67             #returns ECFieldElement (Cartesian)
68             #Used in key generation (not signing … ?)
69             sub get_y {
70 50     50 0 1370 my ($self) = @_;
71              
72 50         185 return $self->_get_x_or_y('y');
73             }
74              
75             sub _get_x_or_y {
76 1016     1016   8110 my ($self, $to_get) = @_;
77              
78 1016 100       7902 if (!defined $self->{'zinv'}) {
79 966         6001 $self->{'zinv'} = $self->{'z'}->copy()->bmodinv($self->{'curve'}{'q'});
80             }
81              
82             return $self->{'curve'}->from_bigint(
83 1016         266897 $self->{$to_get}->to_bigint()->copy()->bmul($self->{'zinv'})->bmod($self->{'curve'}{'q'})
84             );
85             }
86              
87             sub twice {
88 370560     370560 0 698781 my ($self) = @_;
89              
90 370560 50       662845 return $self if $self->is_infinity();
91              
92             #if ($self->{'y'}->to_bigint()->signum() == 0) {
93             # return $self->{'curve'}->get_infinity();
94             #}
95              
96 370560         4440233 my $x1 = $self->{'x'}->to_bigint();
97 370560         771457 my $y1 = $self->{'y'}->to_bigint();
98              
99 370560         961068 my $y1z1 = $y1->copy()->bmul($self->{'z'});
100              
101 370560         25578266 my $y1sqz1 = $y1z1->copy()->bmul($y1)->bmod($self->{'curve'}{'q'});
102              
103 370560         51213857 my $a = $self->{'curve'}{'a'};
104              
105             # w = 3 * x1^2 + a * z1^2
106             #var w = x1.square().multiply(THREE);
107 370560         837024 my $w = $x1->copy()->bpow($bi2)->bmul($bi3);
108              
109 370560 100       82473544 if (!$a->is_zero()) {
110             #$w += ($self->{'z'} ** 2) * $a;
111 330491         3409560 $w->badd( $a->copy()->bmul( $self->{'z'} )->bmul($self->{'z'}) );
112             }
113              
114 370560         55460934 $w->bmod($self->{'curve'}{'q'});
115              
116             # x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
117             #var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
118              
119 370560         29225754 my $x3 = $w->copy()->bmuladd( $w, $y1sqz1->copy()->bmul($x1)->blsft($bi3)->bneg() )->bmul($bi2)->bmul($y1z1);
120             #my $x3 = 2 * $y1z1 * (($w ** 2) - ($x1 << 3) * $y1sqz1);
121             #my $x3 = ($w ** 2) - (($x1 << 3) * $y1sqz1);
122             #$x3 = $x3 << 1;
123             #$x3 *= $y1z1;
124              
125             # y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
126             #var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
127             #my $y3 = 4 * $y1sqz1 * (3 * $w * $x1 - 2 * $y1sqz1) - ($w ** 3);
128              
129 370560         217565272 my $y3 = $y1sqz1->copy()->blsft($bi2);
130              
131 370560         120212609 $y3->bmuladd(
132              
133             #We don’t need y1sqz1 anymore
134             $w->copy()->bmul($bi3)->bmuladd($x1, $y1sqz1->blsft($bi1)->bneg()),
135              
136             #Don’t need $w anymore
137             $w->bpow($bi3)->bneg(),
138             );
139              
140             #// z3 = 8 * (y1 * z1)^3
141             #var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
142             #my $z3 = ($y1z1 ** 3) << 3;
143 370560         273237257 my $z3 = $y1z1->bpow($bi3)->blsft($bi3); #don’t need y1z1 anymore
144              
145             #In original JS logic
146 370560         171902971 $_->bmod($self->{'curve'}{'q'}) for ($x3, $y3, $z3);
147              
148             #return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
149             return (ref $self)->new(
150             $self->{'curve'},
151             $self->{'curve'}->from_bigint($x3),
152 370560         89103815 $self->{'curve'}->from_bigint($y3),
153             $z3,
154             );
155             }
156              
157             #XXX clear
158             sub dump {
159 0     0 0 0 my ($self, $label) = @_;
160              
161 0 0       0 $label = q<> if !defined $label;
162              
163 0         0 printf "$label.x: %s\n", $self->{'x'}->to_bigint()->as_hex();
164 0         0 printf "$label.y: %s\n", $self->{'y'}->to_bigint()->as_hex();
165 0         0 printf "$label.z: %s\n", $self->{'z'}->as_hex();
166             }
167              
168             sub multiply {
169 1431     1431 0 7708 my ($self, $k) = @_;
170              
171 1431 50       6654 if ($self->is_infinity()) {
172 0         0 return $self;
173             }
174              
175             # “Montgomery ladder” algorithm taken from Wikipedia:
176             #
177             # R0 ← 0
178             # R1 ← P
179             # for i from m downto 0 do
180             # if di = 0 then
181             # R1 ← point_add(R0, R1)
182             # R0 ← point_double(R0)
183             # else
184             # R0 ← point_add(R0, R1)
185             # R1 ← point_double(R1)
186             # return R0
187             #
188             # This thwarts the timing attacks that can recover private keys
189             # by running the standard “double-and-add” algorithm over and over
190             # and analyzing response times.
191              
192 1431         30024 my $r0 = ref($self)->new_infinity();
193 1431         7111 my $r1 = $self;
194              
195 1431         13078 for my $i ( reverse( 0 .. ($k->bit_length() - 1) ) ) {
196 370560 100       1363289 if ($k->test_bit($i)) {
197 185579         472990 $r0 = $r0->add($r1);
198 185579         554423 $r1 = $r1->twice();
199             }
200             else {
201 184981         484563 $r1 = $r0->add($r1);
202 184981         570777 $r0 = $r0->twice();
203             }
204             }
205              
206 1431         62157 return $r0;
207             }
208              
209             #$b isa ECPoint
210             sub add {
211 371025     371025 0 689426 my ($self, $b) = @_;
212             #$b->dump('$b');
213              
214             #if(this.isInfinity()) return b;
215             #if(b.isInfinity()) return this;
216              
217 371025 100       685265 return $b if $self->is_infinity();
218 369594 50       4424893 return $self if $b->is_infinity();
219              
220             #// u = Y2 * Z1 - Y1 * Z2
221             #var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
222             my $u = $b->{'y'}->to_bigint()->copy()->bmuladd(
223             $self->{'z'},
224 369594         3898439 $self->{'y'}->to_bigint()->copy()->bneg()->bmul($b->{'z'}),
225             );
226             # $b->{'z'};
227              
228             #// v = X2 * Z1 - X1 * Z2
229             #var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
230             my $v = $b->{'x'}->to_bigint()->copy()->bmuladd(
231             $self->{'z'},
232 369594         65314727 $self->{'x'}->to_bigint()->copy()->bneg()->bmul($b->{'z'}),
233             );
234              
235              
236 369594         62076839 $_->bmod($self->{'curve'}{'q'}) for ($u, $v);
237             #print "u: " . $u->as_hex() . $/;
238             #print "v: " . $v->as_hex() . $/;
239             #if(BigInteger.ZERO.equals(v)) {
240             # if(BigInteger.ZERO.equals(u)) {
241             # return this.twice(); // this == b, so double
242             # }
243             #return this.curve.getInfinity(); // this = -b, so infinity
244             #}
245 369594 50       56120722 if ($v->is_zero()) {
246 0 0       0 if ($u->is_zero()) {
247 0         0 return $self->twice();
248             }
249              
250 0         0 return $self->{'curve'}->get_infinity();
251             }
252              
253             #var THREE = new BigInteger("3");
254             #var x1 = this.x.toBigInteger();
255             #var y1 = this.y.toBigInteger();
256             #var x2 = b.x.toBigInteger();
257             #var y2 = b.y.toBigInteger();
258 369594         3333451 my ($x1, $y1, $z1) = @{$self}{ qw( x y z ) };
  369594         1037692  
259 369594         596487 my ($x2, $y2, $z2) = @{$b}{ qw( x y z ) };
  369594         729979  
260              
261 369594         1099572 $_ = $_->to_bigint() for ($x1, $y1, $x2, $y2);
262              
263             #var v2 = v.square();
264             #var v3 = v2.multiply(v);
265             #var x1v2 = x1.multiply(v2);
266             #var zu2 = u.square().multiply(this.z);
267              
268 369594         898367 my $v2 = $v->copy()->bmul($v);
269 369594         24218921 my $v3 = $v->copy()->bmul($v2);
270              
271 369594         22633883 my $x1v2 = $x1->copy()->bmul($v2);
272 369594         22507356 my $zu2 = $u->copy()->bmul($u)->bmul($self->{'z'});
273             #use Data::Dumper;
274             #print Dumper( map { $_->as_hex() } $u, $v, $x1, $y1, $z1, $x2, $y2, $z2, $v2, $v3, $x1v2, $zu2 );
275              
276             #// x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
277             #var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
278             #my $x3 = $v * ($z2 * ($z1 * ($u ** 2) - 2 * $x1 * ($v ** 2)) - ($v ** 3));
279 369594         38307710 my $x3 = $u->copy()->bmul($u);
280 369594         22557795 $x3->bmuladd( $z1, $x1->copy()->blsft($bi1)->bneg()->bmul($v)->bmul($v) );
281 369594         193322630 $x3->bmuladd( $z2, $v->copy()->bpow($bi3)->bneg() );
282 369594         107055050 $x3->bmul($v);
283              
284             #// y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
285             #var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
286             #my $y3 = $z2 * (3 * $x1 * $u * $v2 - $y1 * $v3 - $z1 * ($u ** 3)) + $u * $v3;
287 369594         17806920 my $y3 = $u->copy()->bmul($bi3)->bmul($x1);
288 369594         39295482 $y3->bmuladd($v2, $y1->copy()->bmul($v3)->bneg()); #no more y1 after this
289 369594         61627745 $y3->bsub( $u->copy()->bpow($bi3)->bmul($z1) );
290              
291 369594         112787269 $y3->bmuladd( $z2, $u->bmul($v3) ); #we don’t need $u anymore
292              
293             #// z3 = v^3 * z1 * z2
294             #var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
295 369594         42820495 my $z3 = $v3->bmul($z1)->bmul($z2);
296              
297 369594         33531114 $_->bmod($self->{'curve'}{'q'}) for ($x3, $y3, $z3);
298              
299             return (ref $self)->new(
300             $self->{'curve'},
301             $self->{'curve'}->from_bigint($x3),
302 369594         90167147 $self->{'curve'}->from_bigint($y3),
303             $z3,
304             );
305             }
306              
307             1;