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) Ashish Gulhati
5             #
6             # $Id: lib/Crypt/EC_DSA.pm v1.009 Tue Oct 16 23:22:27 PDT 2018 $
7              
8             package Crypt::EC_DSA;
9              
10 2     2   110523 use warnings;
  2         11  
  2         56  
11 2     2   9 use strict;
  2         3  
  2         34  
12 2     2   927 use Bytes::Random::Secure;
  2         16609  
  2         92  
13 2     2   763 use Math::EllipticCurve::Prime;
  2         99493  
  2         69  
14 2     2   850 use Digest::SHA qw(sha256_hex);
  2         4121  
  2         147  
15 2     2   12 use vars qw( $VERSION $AUTOLOAD );
  2         5  
  2         1524  
16              
17             our ( $VERSION ) = '$Revision: 1.009 $' =~ /\s+([\d\.]+)/;
18              
19             sub new {
20 1     1 1 69 my ($class, %arg) = @_;
21             bless { debug => $arg{Debug} || 0,
22 1   50     16 curve => Math::EllipticCurve::Prime->from_name($arg{Curve} || 'secp256k1')
      50        
23             }, $class;
24             }
25              
26             sub keygen {
27 1     1 1 4189 my $self = shift;
28 1         9 my $n = $self->curve->n; my $nlen = length($n->as_bin)-2; my $d = 0;
  1         9  
  1         1004  
29 1         7 my $random = Bytes::Random::Secure->new( Bits => 128 );
30 1   66     103 $d = Math::BigInt->from_bin($random->string_from('01',$nlen)) until ($d > 1 and $d < $n);
31 1         3516 my $Q = $self->curve->g->multiply($d);
32 1         10443252 $self->_diag("keygen(): d: $d, Q: x:" . $Q->x . ', y:' . $Q->y . "\n");
33 1         28 return ($Q, $d);
34             }
35              
36             sub sign {
37 1     1 1 480 my ($self, %arg) = @_;
38 1         6 my $n = $self->curve->n; my $nlen = length($n->as_bin);
  1         9  
39 1         1046 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     8 $k = Math::BigInt->from_bin($random->string_from('01',$nlen-2)) until $k > 1 and $k < $n;
44 1         4127 $r = $self->curve->g->multiply($k)->x->bmod($n);
45             }
46 1         12671611 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,$nlen));
47 1         3002 $s = (($z + $arg{Key} * $r) * $k->bmodinv($n))->bmod($n);
48             }
49 1         29521 $self->_diag("sign(): r: $r, s: $s\n");
50 1         25 return ( bless { s => $s,
51             r => $r
52             }, 'Crypt::EC_DSA::Signature' );
53             }
54              
55             sub verify {
56 2     2 1 482 my ($self, %arg) = @_;
57 2         13 my $n = $self->curve->n;
58 2         16 my ($r, $s) = ($arg{Signature}->r, $arg{Signature}->s);
59 2         10 $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         796 my $z = Math::BigInt->new(substr(Math::BigInt->from_hex(sha256_hex($arg{Message}))->as_bin,0,length($n->as_bin)));
62 2         7935 my $w = $s->copy->bmodinv($n);
63 2         52819 my $u1 = ($w * $z)->bmod($n); my $u2 = ($w * $r)->bmod($n);
  2         1997  
64 2         1981 my $x1 = $self->curve->g->multiply($u1)->add($arg{Key}->multiply($u2))->x->bmod($n);
65 2         46562127 $self->_diag("verify(): x1: $x1\nr: $r\n");
66 2         9 $x1 == $r;
67             }
68              
69             sub AUTOLOAD {
70 15     15   447 my $self = shift; (my $auto = $AUTOLOAD) =~ s/.*:://;
  15         89  
71 15 100       174 return if $auto eq 'DESTROY';
72 14 50       66 if ($auto =~ /^(curve|debug)$/x) {
73 14 50       34 $self->{$auto} = shift if (defined $_[0]);
74 14         65 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       45 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   10 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__