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
4             # Copyright (c) 2017 Ashish Gulhati
5             #
6             # $Id: lib/Crypt/EC_DSA.pm v1.007 Thu Jun 8 21:56:53 PDT 2017 $
7              
8             package Crypt::EC_DSA;
9              
10 2     2   27763 use warnings;
  2         4  
  2         62  
11 2     2   9 use strict;
  2         4  
  2         34  
12 2     2   953 use Bytes::Random::Secure;
  2         15616  
  2         89  
13 2     2   800 use Math::EllipticCurve::Prime;
  2         95967  
  2         69  
14 2     2   912 use Digest::SHA qw(sha256_hex);
  2         4038  
  2         136  
15 2     2   14 use vars qw( $VERSION $AUTOLOAD );
  2         4  
  2         1394  
16              
17             our ( $VERSION ) = '$Revision: 1.007 $' =~ /\s+([\d\.]+)/;
18              
19             sub new {
20 1     1 1 18 my ($class, %arg) = @_;
21             bless { debug => $arg{Debug} || 0,
22 1   50     25 curve => Math::EllipticCurve::Prime->from_name($arg{Curve} || 'secp256k1')
      50        
23             }, $class;
24             }
25              
26             sub keygen {
27 1     1 1 4832 my $self = shift;
28 1         9 my $n = $self->curve->n; my $nlen = length($n->as_bin)-2; my $d = 0;
  1         9  
  1         1108  
29 1         10 my $random = Bytes::Random::Secure->new( Bits => 128 );
30 1   66     130 $d = Math::BigInt->from_bin($random->string_from('01',$nlen)) until ($d > 1 and $d < $n);
31 1         94738168 my $Q = $self->curve->g->multiply($d);
32 1         12673614 $self->_diag("keygen(): d: $d, Q: x:" . $Q->x . ', y:' . $Q->y . "\n");
33 1         38 return ($Q, $d);
34             }
35              
36             sub sign {
37 1     1 1 727 my ($self, %arg) = @_;
38 1         6 my $n = $self->curve->n; my $nlen = length($n->as_bin);
  1         9  
39 1         998 my $random = Bytes::Random::Secure->new( Bits => 128 );
40 1         93 my ($k, $r, $s) = (0);
41 1         4 until ($s) {
42 1         4 until ($r) {
43 1   66     16 $k = Math::BigInt->from_bin($random->string_from('01',$nlen-2)) until $k > 1 and $k < $n;
44 1         376224269 $r = $self->curve->g->multiply($k)->x->bmod($n);
45             }
46 1         11935367 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,$nlen));
47 1         2794 $s = (($z + $arg{Key} * $r) * $k->bmodinv($n))->bmod($n);
48             }
49 1         26267 $self->_diag("sign(): r: $r, s: $s\n");
50 1         23 return ( bless { s => $s,
51             r => $r
52             }, 'Crypt::EC_DSA::Signature' );
53             }
54              
55             sub verify {
56 2     2 1 747 my ($self, %arg) = @_;
57 2         13 my $n = $self->curve->n;
58 2         15 my ($r, $s) = ($arg{Signature}->r, $arg{Signature}->s);
59 2         30 $self->_diag("s: $s\nr: $r\n");
60 2 50 33     8 return unless $r > 0 and $r < $n and $s > 0 and $s < $n;
      33        
      33        
61 2         750 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,length($n->as_bin)));
62 2         7466 my $w = $s->copy->bmodinv($n);
63 2         45927 my $u1 = ($w * $z)->bmod($n); my $u2 = ($w * $r)->bmod($n);
  2         1959  
64 2         1947 my $x1 = $self->curve->g->multiply($u1)->add($arg{Key}->multiply($u2))->x->bmod($n);
65 2         49518387 $self->_diag("verify(): x1: $x1\nr: $r\n");
66 2         8 $x1 == $r;
67             }
68              
69             sub AUTOLOAD {
70 15     15   795 my $self = shift; (my $auto = $AUTOLOAD) =~ s/.*:://;
  15         109  
71 15 100       85 return if $auto eq 'DESTROY';
72 14 50       76 if ($auto =~ /^(curve|debug)$/x) {
73 14 50       42 $self->{$auto} = shift if (defined $_[0]);
74 14         79 return $self->{$auto};
75             }
76             else {
77 0         0 die "Could not AUTOLOAD method $auto.";
78             }
79             }
80              
81             sub _diag {
82 6     6   559 my $self = shift;
83 6 50       43 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   7 sub s { shift->{s}; }
93              
94             1; # End of Crypt::EC_DSA::Signature;
95              
96             __END__