File Coverage

blib/lib/Crypt/DSA/Util.pm
Criterion Covered Total %
statement 77 89 86.5
branch 14 24 58.3
condition 5 6 83.3
subroutine 16 18 88.8
pod 5 9 55.5
total 117 146 80.1


line stmt bran cond sub pod time code
1             package Crypt::DSA::Util;
2              
3 6     6   160341 use strict;
  6         10  
  6         283  
4 6     6   33 use Math::BigInt 1.78 try => 'GMP, Pari';
  6         105  
  6         39  
5 6     6   4141 use Crypt::URandom qw (urandom);
  6         47869  
  6         640  
6              
7 6     6   53 use Fcntl;
  6         10  
  6         1790  
8 6     6   44 use Carp qw( croak );
  6         11  
  6         488  
9              
10             our $VERSION = '1.19'; #VERSION
11              
12 6     6   55 use vars qw( $VERSION @ISA @EXPORT_OK );
  6         16  
  6         532  
13 6     6   39 use Exporter;
  6         10  
  6         469  
14              
15             BEGIN {
16 6     6   137 @ISA = qw( Exporter );
17 6         3071 @EXPORT_OK = qw( bitsize bin2mp mp2bin mod_inverse mod_exp makerandom isprime );
18             }
19              
20             ## Nicked from Crypt::RSA::DataFormat.
21             ## Copyright (c) 2001, Vipul Ved Prakash.
22             sub bitsize {
23 7     7 1 9418 length(Math::BigInt->new($_[0])->as_bin) - 2;
24             }
25              
26             sub bin2mp {
27 244     244 1 161445 my $s = shift;
28 244 100       2208 $s eq '' ?
29             Math::BigInt->new(0) :
30             Math::BigInt->new("0b" . unpack("B*", $s));
31             }
32              
33             sub mp2bin {
34 3     3 1 4459 my $p = Math::BigInt->new(shift);
35 3         206 my $base = Math::BigInt->new(256);
36 3         236 my $res = '';
37 3         28 while ($p != 0) {
38 41         7551 my $r = $p % $base;
39 41         4707 $p = ($p-$r) / $base;
40 41         14728 $res = chr($r) . $res;
41             }
42 3         574 $res;
43             }
44              
45             sub mod_exp {
46 6     6 1 264 my($a, $exp, $n) = @_;
47 6         46 $a->copy->bmodpow($exp, $n);
48             }
49              
50             sub mod_inverse {
51 3     3 1 2997 my($a, $n) = @_;
52 3         17 $a->copy->bmodinv($n);
53             }
54              
55             sub makerandom {
56 2     2 0 809 my %param = @_;
57 2         14 my $size = $param{Size};
58 2         16 my $bytes = int($size / 8) + 1;
59 2         70 my $r = urandom($bytes);
60 2         182 my $down = $size - 1;
61 2 50       55 $r = unpack 'H*', pack 'B*', '0' x ( $size % 8 ? 8 - $size % 8 : 0 ) .
62             '1' . unpack "b$down", $r;
63 2         13 Math::BigInt->new('0x' . $r);
64             }
65              
66             # For testing, let us choose our isprime function:
67             *isprime = \&isprime_algorithms_with_perl;
68              
69             # from the book "Mastering Algorithms with Perl" by Jon Orwant,
70             # Jarkko Hietaniemi, and John Macdonald
71             sub isprime_algorithms_with_perl {
72 6     6   51 use integer;
  6         11  
  6         43  
73 86     86 0 3391 my $n = shift;
74 86         363 my $n1 = $n - 1;
75 86         28078 my $one = $n - $n1; # not just 1, but a bigint
76 86         23140 my $witness = $one * 100;
77              
78             # find the power of two for the top bit of $n1
79 86         23550 my $p2 = $one;
80 86         175 my $p2index = -1;
81 86         408 ++$p2index, $p2 *= 2
82             while $p2 <= $n1;
83 86         9968109 $p2 /= 2;
84              
85             # number of interations: 5 for 260-bit numbers, go up to 25 for smaller
86 86         44030 my $last_witness = 5;
87 86 100       514 $last_witness += (260 - $p2index) / 13 if $p2index < 260;
88              
89 86         343 for my $witness_count (1..$last_witness) {
90 101         3298 $witness *= 1024;
91 101         26456 $witness += int(rand(1024)); # XXXX use good rand
92 101 50       29807 $witness = $witness % $n if $witness > $n;
93 101 50       5597 $witness = $one * 100, redo if $witness == 0;
94              
95 101         21420 my $prod = $one;
96 101         238 my $n1bits = $n1;
97 101         172 my $p2next = $p2;
98              
99             # compute $witness ** ($n - 1)
100 101         197 while (1) {
101 35520   100     14696483 my $rootone = $prod == 1 || $prod == $n1;
102 35520         8608766 $prod = ($prod * $prod) % $n;
103 35520 50 66     91001337 return 0 if $prod == 1 && ! $rootone;
104 35520 100       7579231 if ($n1bits >= $p2next) {
105 17994         882568 $prod = ($prod * $witness) % $n;
106 17994         10818965 $n1bits -= $p2next;
107             }
108 35520 100       4155045 last if $p2next == 1;
109 35419         7086023 $p2next /= 2;
110             }
111 101 100       19641 return 0 unless $prod == 1;
112             }
113 2         516 return 1;
114             }
115              
116             sub isprime_gp_pari {
117 0     0 0   my $n = shift;
118              
119 0           my $sn = "$n";
120 0 0         die if $sn =~ /\D/;
121              
122 0           my $is_prime = `echo "isprime($sn)" | gp -f -q`;
123 0 0         die "No gp installed?" if $?;
124              
125 0           chomp $is_prime;
126 0           return $is_prime;
127             }
128              
129             sub isprime_paranoid {
130 0     0 0   my $n = shift;
131              
132 0           my $perl = isprime_algorithms_with_perl($n);
133 0           my $pari = isprime_gp_pari($n);
134              
135 0 0         die "Perl vs. PARI don't match on '$n'\n" unless $perl == $pari;
136 0           return $perl;
137             }
138              
139             1;
140             __END__