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 6     6   164961 use strict;
  6         12  
  6         756  
4 6     6   32 use warnings;
  6         11  
  6         364  
5 6     6   34 use Math::BigInt 1.78 try => 'GMP, Pari';
  6         152  
  6         65  
6 6     6   4566 use Crypt::URandom qw (urandom);
  6         35883  
  6         483  
7              
8 6     6   50 use Fcntl;
  6         13  
  6         1888  
9 6     6   43 use Carp qw( croak );
  6         12  
  6         515  
10              
11             our $VERSION = '1.20'; #VERSION
12              
13 6     6   39 use vars qw( $VERSION @ISA @EXPORT_OK );
  6         10  
  6         453  
14 6     6   40 use Exporter;
  6         68  
  6         464  
15              
16             BEGIN {
17 6     6   121 @ISA = qw( Exporter );
18 6         3364 @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 7     7 1 9865 length(Math::BigInt->new($_[0])->as_bin) - 2;
25             }
26              
27             sub bin2mp {
28 778     778 1 250030 my $s = shift;
29 778 100       6133 $s eq '' ?
30             Math::BigInt->new(0) :
31             Math::BigInt->new("0b" . unpack("B*", $s));
32             }
33              
34             sub mp2bin {
35 3     3 1 5270 my $p = Math::BigInt->new(shift);
36 3         320 my $base = Math::BigInt->new(256);
37 3         305 my $res = '';
38 3         15 while ($p != 0) {
39 41         11798 my $r = $p % $base;
40 41         7275 $p = ($p-$r) / $base;
41 41         27759 $res = chr($r) . $res;
42             }
43 3         846 $res;
44             }
45              
46             sub mod_exp {
47 6     6 1 543 my($a, $exp, $n) = @_;
48 6         53 $a->copy->bmodpow($exp, $n);
49             }
50              
51             sub mod_inverse {
52 3     3 1 3973 my($a, $n) = @_;
53 3         19 $a->copy->bmodinv($n);
54             }
55              
56             sub makerandom {
57 2     2 0 885 my %param = @_;
58 2         15 my $size = $param{Size};
59 2         17 my $bytes = int($size / 8) + 1;
60 2         71 my $r = urandom($bytes);
61 2         186 my $down = $size - 1;
62 2 50       43 $r = unpack 'H*', pack 'B*', '0' x ( $size % 8 ? 8 - $size % 8 : 0 ) .
63             '1' . unpack "b$down", $r;
64 2         30 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 6     6   55 use integer;
  6         13  
  6         61  
74 200     200 0 12058 my $n = shift;
75 200         585 my $n1 = $n - 1;
76 200         64173 my $one = $n - $n1; # not just 1, but a bigint
77 200         60409 my $witness = $one * 100;
78              
79             # find the power of two for the top bit of $n1
80 200         54553 my $p2 = $one;
81 200         471 my $p2index = -1;
82 200         926 ++$p2index, $p2 *= 2
83             while $p2 <= $n1;
84 200         31019169 $p2 /= 2;
85              
86             # number of iterations: 5 for 260-bit numbers, go up to 25 for smaller
87 200         105211 my $last_witness = 5;
88 200 100       915 $last_witness += (260 - $p2index) / 13 if $p2index < 260;
89              
90 200         663 for my $witness_count (1..$last_witness) {
91 215         3458 $witness *= 1024;
92 215         56206 $witness += int(rand(1024)); # XXXX use good rand
93 215 50       64303 $witness = $witness % $n if $witness > $n;
94 215 50       11448 $witness = $one * 100, redo if $witness == 0;
95              
96 215         43685 my $prod = $one;
97 215         432 my $n1bits = $n1;
98 215         392 my $p2next = $p2;
99              
100             # compute $witness ** ($n - 1)
101 215         382 while (1) {
102 103040   100     42945638 my $rootone = $prod == 1 || $prod == $n1;
103 103040         25061257 $prod = ($prod * $prod) % $n;
104 103040 50 66     303043737 return 0 if $prod == 1 && ! $rootone;
105 103040 100       21883831 if ($n1bits >= $p2next) {
106 51437         2555477 $prod = ($prod * $witness) % $n;
107 51437         31910555 $n1bits -= $p2next;
108             }
109 103040 100       12143990 last if $p2next == 1;
110 102825         20654291 $p2next /= 2;
111             }
112 215 100       40879 return 0 unless $prod == 1;
113             }
114 2         408 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__