File Coverage

blib/lib/Crypt/EC_DSA.pm
Criterion Covered Total %
statement 64 65 98.4
branch 6 10 60.0
condition 9 19 47.3
subroutine 14 14 100.0
pod 4 4 100.0
total 97 112 86.6


line stmt bran cond sub pod time code
1             # -*-cperl-*-
2             #
3             # Crypt::EC_DSA - Elliptic Curve Digital Signature Algorithm (ECDSA)
4             # Copyright (c) 2017 Ashish Gulhati
5             #
6             # $Id: lib/Crypt/EC_DSA.pm v1.008 Thu Jun 8 22:19:29 PDT 2017 $
7              
8             package Crypt::EC_DSA;
9              
10 2     2   27269 use warnings;
  2         5  
  2         68  
11 2     2   12 use strict;
  2         5  
  2         41  
12 2     2   904 use Bytes::Random::Secure;
  2         14884  
  2         86  
13 2     2   790 use Math::EllipticCurve::Prime;
  2         85914  
  2         71  
14 2     2   905 use Digest::SHA qw(sha256_hex);
  2         4250  
  2         150  
15 2     2   13 use vars qw( $VERSION $AUTOLOAD );
  2         4  
  2         1359  
16              
17             our ( $VERSION ) = '$Revision: 1.008 $' =~ /\s+([\d\.]+)/;
18              
19             sub new {
20 1     1 1 10 my ($class, %arg) = @_;
21             bless { debug => $arg{Debug} || 0,
22 1   50     15 curve => Math::EllipticCurve::Prime->from_name($arg{Curve} || 'secp256k1')
      50        
23             }, $class;
24             }
25              
26             sub keygen {
27 1     1 1 4818 my $self = shift;
28 1         8 my $n = $self->curve->n; my $nlen = length($n->as_bin)-2; my $d = 0;
  1         8  
  1         1019  
29 1         7 my $random = Bytes::Random::Secure->new( Bits => 128 );
30 1   66     104 $d = Math::BigInt->from_bin($random->string_from('01',$nlen)) until ($d > 1 and $d < $n);
31 1         3984 my $Q = $self->curve->g->multiply($d);
32 1         12039870 $self->_diag("keygen(): d: $d, Q: x:" . $Q->x . ', y:' . $Q->y . "\n");
33 1         47 return ($Q, $d);
34             }
35              
36             sub sign {
37 1     1 1 481 my ($self, %arg) = @_;
38 1         6 my $n = $self->curve->n; my $nlen = length($n->as_bin);
  1         9  
39 1         1323 my $random = Bytes::Random::Secure->new( Bits => 128 );
40 1         92 my ($k, $r, $s) = (0);
41 1         4 until ($s) {
42 1         3 until ($r) {
43 1   66     15 $k = Math::BigInt->from_bin($random->string_from('01',$nlen-2)) until $k > 1 and $k < $n;
44 1         194295926 $r = $self->curve->g->multiply($k)->x->bmod($n);
45             }
46 1         12100098 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,$nlen));
47 1         2804 $s = (($z + $arg{Key} * $r) * $k->bmodinv($n))->bmod($n);
48             }
49 1         24028 $self->_diag("sign(): r: $r, s: $s\n");
50 1         27 return ( bless { s => $s,
51             r => $r
52             }, 'Crypt::EC_DSA::Signature' );
53             }
54              
55             sub verify {
56 2     2 1 748 my ($self, %arg) = @_;
57 2         12 my $n = $self->curve->n;
58 2         16 my ($r, $s) = ($arg{Signature}->r, $arg{Signature}->s);
59 2         23 $self->_diag("s: $s\nr: $r\n");
60 2 50 33     9 return unless $r > 0 and $r < $n and $s > 0 and $s < $n;
      33        
      33        
61 2         770 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,length($n->as_bin)));
62 2         7508 my $w = $s->copy->bmodinv($n);
63 2         50835 my $u1 = ($w * $z)->bmod($n); my $u2 = ($w * $r)->bmod($n);
  2         1984  
64 2         1934 my $x1 = $self->curve->g->multiply($u1)->add($arg{Key}->multiply($u2))->x->bmod($n);
65 2         48488554 $self->_diag("verify(): x1: $x1\nr: $r\n");
66 2         13 $x1 == $r;
67             }
68              
69             sub AUTOLOAD {
70 15     15   794 my $self = shift; (my $auto = $AUTOLOAD) =~ s/.*:://;
  15         92  
71 15 100       84 return if $auto eq 'DESTROY';
72 14 50       65 if ($auto =~ /^(curve|debug)$/x) {
73 14 50       38 $self->{$auto} = shift if (defined $_[0]);
74 14         70 return $self->{$auto};
75             }
76             else {
77 0         0 die "Could not AUTOLOAD method $auto.";
78             }
79             }
80              
81             sub _diag {
82 6     6   609 my $self = shift;
83 6 50       54 print STDERR @_ if $self->debug;
84             }
85              
86             1; # End of Crypt::EC_DSA
87              
88             package Crypt::EC_DSA::Signature;
89              
90 2     2   9 sub r { shift->{r}; }
91              
92 2     2   5 sub s { shift->{s}; }
93              
94             1; # End of Crypt::EC_DSA::Signature;
95              
96             __END__