File Coverage

blib/lib/Crypt/DSA/Util.pm
Criterion Covered Total %
statement 80 92 86.9
branch 14 24 58.3
condition 5 6 83.3
subroutine 17 19 89.4
pod 5 9 55.5
total 121 150 80.6


line stmt bran cond sub pod time code
1             package Crypt::DSA::Util;
2              
3 7     7   139570 use strict;
  7         10  
  7         184  
4 7     7   22 use warnings;
  7         10  
  7         274  
5 7     7   23 use Math::BigInt 1.78 try => 'GMP, Pari';
  7         146  
  7         43  
6 7     7   3626 use Crypt::URandom qw (urandom);
  7         27050  
  7         350  
7              
8 7     7   44 use Fcntl;
  7         10  
  7         1414  
9 7     7   33 use Carp qw( croak );
  7         8  
  7         415  
10              
11             our $VERSION = '1.21'; #VERSION
12              
13 7     7   31 use vars qw( $VERSION @ISA @EXPORT_OK );
  7         11  
  7         378  
14 7     7   30 use Exporter;
  7         17  
  7         397  
15              
16             BEGIN {
17 7     7   84 @ISA = qw( Exporter );
18 7         2494 @EXPORT_OK = qw( bitsize bin2mp mp2bin mod_inverse mod_exp makerandom isprime );
19             }
20              
21             ## Nicked from Crypt::RSA::DataFormat.
22             ## Copyright (c) 2001, Vipul Ved Prakash.
23             sub bitsize {
24 12     12 1 5677 length(Math::BigInt->new($_[0])->as_bin) - 2;
25             }
26              
27             sub bin2mp {
28 1326     1326 1 152128 my $s = shift;
29 1326 100       8492 $s eq '' ?
30             Math::BigInt->new(0) :
31             Math::BigInt->new("0b" . unpack("B*", $s));
32             }
33              
34             sub mp2bin {
35 3     3 1 2838 my $p = Math::BigInt->new(shift);
36 3         164 my $base = Math::BigInt->new(256);
37 3         167 my $res = '';
38 3         8 while ($p != 0) {
39 41         5957 my $r = $p % $base;
40 41         3578 $p = ($p-$r) / $base;
41 41         10422 $res = chr($r) . $res;
42             }
43 3         393 $res;
44             }
45              
46             sub mod_exp {
47 10     10 1 263 my($a, $exp, $n) = @_;
48 10         47 $a->copy->bmodpow($exp, $n);
49             }
50              
51             sub mod_inverse {
52 5     5 1 2108 my($a, $n) = @_;
53 5         29 $a->copy->bmodinv($n);
54             }
55              
56             sub makerandom {
57 5     5 0 1395 my %param = @_;
58 5         13 my $size = $param{Size};
59 5         12 my $bytes = int($size / 8) + 1;
60 5         108 my $r = urandom($bytes);
61 5         208 my $down = $size - 1;
62 5 50       62 $r = unpack 'H*', pack 'B*', '0' x ( $size % 8 ? 8 - $size % 8 : 0 ) .
63             '1' . unpack "b$down", $r;
64 5         19 Math::BigInt->new('0x' . $r);
65             }
66              
67             # For testing, let us choose our isprime function:
68             *isprime = \&isprime_algorithms_with_perl;
69              
70             # from the book "Mastering Algorithms with Perl" by Jon Orwant,
71             # Jarkko Hietaniemi, and John Macdonald
72             sub isprime_algorithms_with_perl {
73 7     7   45 use integer;
  7         6  
  7         56  
74 456     456 0 12032 my $n = shift;
75 456         1105 my $n1 = $n - 1;
76 456         98115 my $one = $n - $n1; # not just 1, but a bigint
77 456         79519 my $witness = $one * 100;
78              
79             # find the power of two for the top bit of $n1
80 456         81286 my $p2 = $one;
81 456         633 my $p2index = -1;
82 456         1584 ++$p2index, $p2 *= 2
83             while $p2 <= $n1;
84 456         33417999 $p2 /= 2;
85              
86             # number of iterations: 5 for 260-bit numbers, go up to 25 for smaller
87 456         151743 my $last_witness = 5;
88 456 100       1698 $last_witness += (260 - $p2index) / 13 if $p2index < 260;
89              
90 456         1219 for my $witness_count (1..$last_witness) {
91 486         4692 $witness *= 1024;
92 486         81349 $witness += int(rand(1024)); # XXXX use good rand
93 486 50       92163 $witness = $witness % $n if $witness > $n;
94 486 50       17831 $witness = $one * 100, redo if $witness == 0;
95              
96 486         63663 my $prod = $one;
97 486         759 my $n1bits = $n1;
98 486         662 my $p2next = $p2;
99              
100             # compute $witness ** ($n - 1)
101 486         669 while (1) {
102 181600   100     48102452 my $rootone = $prod == 1 || $prod == $n1;
103 181600         28571709 $prod = ($prod * $prod) % $n;
104 181600 50 66     311927884 return 0 if $prod == 1 && ! $rootone;
105 181600 100       24925653 if ($n1bits >= $p2next) {
106 91207         2957563 $prod = ($prod * $witness) % $n;
107 91207         35296907 $n1bits -= $p2next;
108             }
109 181600 100       13661682 last if $p2next == 1;
110 181114         23326555 $p2next /= 2;
111             }
112 486 100       59576 return 0 unless $prod == 1;
113             }
114 4         580 return 1;
115             }
116              
117             sub isprime_gp_pari {
118 0     0 0   my $n = shift;
119              
120 0           my $sn = "$n";
121 0 0         die if $sn =~ /\D/;
122              
123 0           my $is_prime = `echo "isprime($sn)" | gp -f -q`;
124 0 0         die "No gp installed?" if $?;
125              
126 0           chomp $is_prime;
127 0           return $is_prime;
128             }
129              
130             sub isprime_paranoid {
131 0     0 0   my $n = shift;
132              
133 0           my $perl = isprime_algorithms_with_perl($n);
134 0           my $pari = isprime_gp_pari($n);
135              
136 0 0         die "Perl vs. PARI don't match on '$n'\n" unless $perl == $pari;
137 0           return $perl;
138             }
139              
140             1;
141             __END__