File Coverage

blib/lib/Crypt/DSA/GMP/Util.pm
Criterion Covered Total %
statement 70 70 100.0
branch 16 24 66.6
condition 6 12 50.0
subroutine 16 16 100.0
pod 8 8 100.0
total 116 130 89.2


line stmt bran cond sub pod time code
1             package Crypt::DSA::GMP::Util;
2 1     1   71534 use strict;
  1         3  
  1         38  
3 1     1   5 use warnings;
  1         3  
  1         47  
4              
5             BEGIN {
6 1     1   2 $Crypt::DSA::GMP::Util::AUTHORITY = 'cpan:DANAJ';
7 1         18 $Crypt::DSA::GMP::Util::VERSION = '0.01';
8             }
9              
10 1     1   6 use Carp qw( croak );
  1         3  
  1         82  
11 1     1   6 use Math::BigInt lib => "GMP";
  1         2  
  1         8  
12 1     1   2371 use Crypt::Random::Seed;
  1         3458  
  1         55  
13              
14 1     1   9 use base qw( Exporter );
  1         2  
  1         1033  
15             our @EXPORT_OK = qw( bitsize bin2mp mp2bin mod_inverse mod_exp randombytes makerandom makerandomrange );
16             our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
17              
18             sub bitsize {
19 4     4 1 4113 my $n = shift;
20 4 100       22 $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
21 4         56 length($n->as_bin) - 2;
22             }
23              
24             # This is the os2ip function
25             sub bin2mp {
26 3     3 1 155 my $s = shift;
27 3 100 66     22 return Math::BigInt->new(0) if !defined $s || $s eq '';
28 2         16 return Math::BigInt->from_hex('0x' . unpack("H*", $s));
29             }
30              
31             # This is the i2osp function
32             sub mp2bin {
33 4     4 1 2204 my $p = shift;
34 4         6 my $res = '';
35 4 100 66     21 if (ref($p) ne 'Math::BigInt' && $p <= ~0) {
36 1         2 do {
37 4         8 $res = chr($p & 0xFF) . $res;
38 4         9 $p >>= 8;
39             } while $p;
40             } else {
41 3 50       9 $p = Math::BigInt->new("$p") unless ref($p) eq 'Math::BigInt';
42 3         11 my $hex = $p->as_hex;
43 3         824 $hex =~ s/^0x0*//;
44 3 50       9 substr($hex, 0, 0, '0') if length($hex) % 2;
45 3         12 $res = pack("H*", $hex);
46             }
47 4         16 $res;
48             }
49              
50             sub mod_exp {
51 1     1 1 103 my($a, $exp, $n) = @_;
52 1         6 $a->copy->bmodpow($exp, $n);
53             }
54              
55             sub mod_inverse {
56 1     1 1 1578 my($a, $n) = @_;
57 1         4 $a->copy->bmodinv($n);
58             }
59              
60             {
61             my ($crs, $crs_best);
62             sub _setup_rng {
63 1     1   10 $crs_best = Crypt::Random::Seed->new();
64 1 50       194 $crs = ($crs_best->is_blocking())
65             ? Crypt::Random::Seed->new(NonBlocking=>1)
66             : $crs_best;
67             }
68             sub randombytes {
69 2     2 1 4 my($bytes, $keygen) = @_;
70 2 100       9 _setup_rng() unless defined $crs;
71 2 50       134 my $src = ($keygen) ? $crs_best : $crs;
72 2         9 return $src->random_bytes($bytes);
73             }
74             }
75              
76             # Generate uniform random number in range [2^(bits-1),2^bits-1]
77             sub makerandom {
78 1     1 1 2425 my %param = @_;
79 1         4 my ($bits, $is_keygen) = ( $param{Size}, $param{KeyGen} );
80 1 50 33     28 croak "makerandom must have Size >= 1" unless defined $bits && $bits > 0;
81 1 50       5 return Math::BigInt->bone if $bits == 1;
82              
83 1         2 my $randbits = $bits - 1;
84 1         3 my $randbytes = int(($randbits+7)/8);
85 1         4 my $randbinary = unpack("B*", randombytes( $randbytes, $is_keygen ));
86 1         108 return Math::BigInt->from_bin( '0b1' . substr($randbinary,0,$randbits) );
87             }
88              
89             # Generate uniform random number in range [0, $max]
90             sub makerandomrange {
91 1     1 1 1381 my %param = @_;
92 1         3 my ($max, $is_keygen) = ( $param{Max}, $param{KeyGen} );
93 1 50 33     7 croak "makerandomrange must have a Max > 0" unless defined $max && $max > 0;
94 1 50       125 $max = Math::BigInt->new("$max") unless ref($max) eq 'Math::BigInt';
95 1         4 my $range = $max->copy->binc;
96 1         52 my $bits = length($range->as_bin) - 2;
97 1         288 my $bytes = 1 + int(($bits+7)/8);
98 1         6 my $rmax = Math::BigInt->bone->blsft(8*$bytes)->bdec();
99 1         371 my $overflow = $rmax - ($rmax % $range);
100 1         258 my $U;
101 1         2 do {
102 1         3 $U = Math::BigInt->from_hex( '0x' . unpack("H*", randombytes($bytes,$is_keygen)) );
103             } while $U >= $overflow;
104 1         419 $U->bmod($range); # U is randomly in [0, k*$range-1] for some k.
105 1         114 return $U;
106             }
107              
108             1;
109             __END__