File Coverage

blib/lib/Data/Entropy/Source.pm
Criterion Covered Total %
statement 115 123 93.5
branch 49 62 79.0
condition 7 9 77.7
subroutine 13 13 100.0
pod 5 5 100.0
total 189 212 89.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Data::Entropy::Source - encapsulated source of entropy
4              
5             =head1 SYNOPSIS
6              
7             use Data::Entropy::Source;
8              
9             $source = Data::Entropy::Source->new($handle, "sysread");
10              
11             $c = $source->get_octet;
12             $str = $source->get_bits(17);
13             $i = $source->get_int(12345);
14             $i = $source->get_int(Math::BigInt->new("1000000000000"));
15             $j = $source->get_prob(1, 2);
16              
17             =head1 DESCRIPTION
18              
19             An object of this class encapsulates a source of entropy
20             (randomness). Methods allow entropy to be dispensed in any
21             quantity required, even fractional bits. An entropy source object
22             should not normally be used directly. Rather, it should be used to
23             support higher-level entropy-consuming algorithms, such as those in
24             L.
25              
26             This type of object is constructed as a layer over a raw entropy source
27             which does not supply methods to extract arbitrary amounts of entropy.
28             The raw entropy source is expected to dispense only entire octets at
29             a time. The B devices on some versions of Unix constitute
30             such a source, for example. The raw entropy source is accessed
31             via the C interface. This interface may be supplied by
32             classes other than C itself, as is done for example by
33             C.
34              
35             If two entropy sources of this class are given exactly the same raw
36             entropy data, for example by reading from the same file, and exactly the
37             same sequence of C method calls is made to them, then they will
38             return exactly the same values from those calls. (Calls with numerical
39             arguments that have the same numerical value but are of different
40             types count as the same for this purpose.) This means that a run of an
41             entropy-using algorithm can be made completely deterministic if desired.
42              
43             =cut
44              
45             package Data::Entropy::Source;
46              
47 18     18   1194399 { use 5.006; }
  18         72  
  18         1132  
48 18     18   135 use warnings;
  18         112  
  18         596  
49 18     18   100 use strict;
  18         36  
  18         701  
50              
51 18     18   111 use Carp qw(croak);
  18         45  
  18         8383  
52              
53             our $VERSION = "0.007";
54              
55             =head1 CONSTRUCTOR
56              
57             =over
58              
59             =item Data::Entropy::Source->new(RAW_SOURCE, READ_STYLE)
60              
61             Constructs and returns an entropy source object based on the given raw
62             source. RAW_SOURCE must be an I/O handle referring to a source of entropy
63             that can be read one octet at a time. Specifically, it must support
64             either the C or C method described in L.
65             READ_STYLE must be a string, either "getc" or "sysread", indicating which
66             method should be used to read from the raw source. No methods other
67             than the one specified will ever be called on the raw source handle,
68             so a full implementation of C is not required.
69              
70             The C method should be used with B and its ilk,
71             because buffering would be very wasteful of entropy and might consequently
72             block other processes that require entropy. C should be preferred
73             when reading entropy from a regular file, and it is the more convenient
74             interface to implement when a non-I/O object is being used for the handle.
75              
76             =cut
77              
78             sub new {
79 20     20 1 162265 my($class, $rawsrc, $readstyle) = @_;
80 20 50       106 croak "no raw entropy source given" unless defined $rawsrc;
81 20 50       162 croak "read style `$readstyle' not recognised"
82             unless $readstyle =~ /\A(?:getc|sysread)\z/;
83 20         258 return bless({
84             rawsrc => $rawsrc,
85             readstyle => $readstyle,
86             limit => 1,
87             num => 0,
88             }, $class);
89             }
90              
91             =back
92              
93             =head1 METHODS
94              
95             =over
96              
97             =item $source->get_octet
98              
99             Returns an octet of entropy, as a string of length one. This provides
100             direct access to the raw entropy source.
101              
102             =cut
103              
104             sub get_octet {
105 72862     72862 1 1515295 my($self) = @_;
106 72862 50       191113 if($self->{readstyle} eq "getc") {
    0          
107 72862         169254 my $errno = $!;
108 72862         105553 $! = 0;
109 72862         283057 my $octet = $self->{rawsrc}->getc;
110 72862 100       274331 unless(defined $octet) {
111 4         26 my $errmsg = $!;
112 4 50       18 unless($errmsg) {
113 0         0 $errmsg = "EOF";
114 0         0 $! = $errno;
115             }
116 4         1071 croak "entropy source failed: $errmsg";
117             }
118 72858         130124 $! = $errno;
119 72858         333829 return $octet;
120             } elsif($self->{readstyle} eq "sysread") {
121 0         0 my $octet;
122 0         0 my $n = $self->{rawsrc}->sysread($octet, 1);
123 0 0       0 croak "entropy source failed: ".(defined($n) ? $! : "EOF")
    0          
124             unless $n;
125 0         0 return $octet;
126             }
127             }
128              
129             # ->_get_small_int may be used only with a native integer argument, up to 256.
130              
131             sub _get_small_int {
132 34951     34951   55319 my($self, $limit) = @_;
133 18     18   14200 use integer;
  18         149  
  18         122  
134 34951         59261 my $reqlimit = $limit << 15;
135 34951         49802 while(1) {
136 34951         111215 while($self->{limit} < $reqlimit) {
137 15342         39864 $self->{num} = ($self->{num} << 8) +
138             ord($self->get_octet);
139 15341         72610 $self->{limit} <<= 8;
140             }
141 34950         60111 my $rep = $self->{limit} / $limit;
142 34950         55785 my $uselimit = $rep * $limit;
143 34950 50       108058 if($self->{num} < $uselimit) {
144 34950         48611 my $num = $self->{num} / $rep;
145 34950         51793 $self->{num} %= $rep;
146 34950         54125 $self->{limit} = $rep;
147 34950         98024 return $num;
148             }
149 0         0 $self->{num} -= $uselimit;
150 0         0 $self->{limit} -= $uselimit;
151             }
152             }
153              
154             # ->_put_small_int is used to return the unused portion of some entropy that
155             # was extracted using ->_get_small_int.
156              
157             sub _put_small_int {
158 2945     2945   5155 my($self, $limit, $num) = @_;
159 2945         10092 $self->{limit} *= $limit;
160 2945         6831 $self->{num} = $self->{num} * $limit + $num;
161             }
162              
163             =item $source->get_bits(NBITS)
164              
165             Returns NBITS bits of entropy, as a string of octets. If NBITS is
166             not a multiple of eight then the last octet in the string has its most
167             significant bits set to zero.
168              
169             =cut
170              
171             sub get_bits {
172 222     222 1 158156 my($self, $nbits) = @_;
173 222         739 my $nbytes = $nbits >> 3;
174 222         265 $nbits &= 7;
175 222         302 my $str = "";
176 222         999 $str .= $self->get_octet while $nbytes--;
177 221 100       822 $str .= chr($self->_get_small_int(1 << $nbits)) if $nbits;
178 221         25954 return $str;
179             }
180              
181             =item $source->get_int(LIMIT)
182              
183             LIMIT must be a positive integer. Returns a uniformly-distributed
184             random number between zero inclusive and LIMIT exclusive. LIMIT may be
185             either a native integer, a C object, or an integer-valued
186             C object; the returned number is of the same type.
187              
188             This method dispenses a non-integer number of bits of entropy.
189             For example, if LIMIT is 10 then the result contains approximately 3.32
190             bits of entropy. The minimum non-zero amount of entropy that can be
191             obtained is 1 bit, with LIMIT = 2.
192              
193             =cut
194              
195             sub _break_int {
196 33012     33012   584906 my($num) = @_;
197 33012         58637 my $type = ref($num);
198 33012 100       88546 $num = $num->as_number if $type eq "Math::BigRat";
199 33012         72639 my @limbs;
200 33012         81825 while($num != 0) {
201 92464         1599974 my $l = $num & 255;
202 92464 100       1382727 $l = $l->numify if $type ne "";
203 92464         234023 push @limbs, $l;
204 92464         236152 $num >>= 8;
205             }
206 33012         620320 return \@limbs;
207             }
208              
209             sub get_int {
210 27312     27312 1 4259741 my($self, $limit) = @_;
211 27312         44536 my $type = ref($limit);
212 27312         76758 my $max = _break_int($limit - 1);
213 27312         52298 my $len = @$max;
214 27312         37547 my @num_limbs;
215 27312 100       72598 if($len) {
216 27116         31200 TRY_AGAIN:
217             my $i = $len;
218 27116         39673 my $ml = $max->[--$i];
219 27116         84242 my $nl = $self->_get_small_int($ml + 1);
220 27115         57433 @num_limbs = ($nl);
221 27115   100     149200 while($i && $nl == $ml) {
222 4182         6151 $ml = $max->[--$i];
223 4182         14744 $nl = $self->_get_small_int(256);
224 4182 100       20345 if($nl > $ml) {
225 65         271 $self->_put_small_int(255-$ml, $nl-$ml-1);
226 65         624 goto TRY_AGAIN;
227             }
228 4117         33454 push @num_limbs, $nl;
229             }
230 27050         101416 push @num_limbs, ord($self->get_octet) while $i--;
231             }
232 27310 100       63820 my $num = $type eq "" ? 0 : Math::BigInt->new(0);
233 27310         177027 for(my $i = $len; $i--; ) {
234 84577         1229157 my $l = $num_limbs[$len-1-$i];
235 84577 100       173860 $l = Math::BigInt->new($l) if $type ne "";
236 84577         383182 $num += $l << ($i << 3);
237             }
238 27310 100       446948 $num = Math::BigRat->new($num) if $type eq "Math::BigRat";
239 27310         249379 return $num;
240             }
241              
242             =item $source->get_prob(PROB0, PROB1)
243              
244             PROB0 and PROB1 must be non-negative integers, not both zero.
245             They may each be either a native integer, a C object,
246             or an integer-valued C objects; types may be mixed.
247             Returns either 0 or 1, with relative probabilities PROB0 and PROB1.
248             That is, the probability of returning 0 is PROB0/(PROB0+PROB1), and the
249             probability of returning 1 is PROB1/(PROB0+PROB1).
250              
251             This method dispenses a fraction of a bit of entropy. The maximum
252             amount of entropy that can be obtained is 1 bit, with PROB0 = PROB1.
253             The more different the probabilities are the less entropy is obtained.
254             For example, if PROB0 = 1 and PROB1 = 2 then the result contains
255             approximately 0.918 bits of entropy.
256              
257             =cut
258              
259             sub get_prob {
260 3034     3034 1 1756977 my($self, $prob0, $prob1) = @_;
261 3034 50 33     17753 croak "probabilities must be non-negative"
262             unless $prob0 >= 0 && $prob1 >= 0;
263 3034 100       10501 if($prob0 == 0) {
    100          
264 49 50       111 croak "can't have nothing possible" if $prob1 == 0;
265 49         255 return 1;
266             } elsif($prob1 == 0) {
267 135         525 return 0;
268             }
269 2850         8422 my $max0 = _break_int($prob0 - 1);
270 2850         12738 my $maxt = _break_int($prob0 + $prob1 - 1);
271 2850         4965 my $len = @$maxt;
272 2850 100       14042 push @$max0, (0) x ($len - @$max0) unless @$max0 == $len;
273 2880         3767 TRY_AGAIN:
274             my $maybe0 = 1;
275 2880         3407 my $maybebad = 1;
276 2880         3753 my($mtl, $m0l, $nl);
277 2880         6367 for(my $i = $len - 1; ; $i--) {
278 3460 100       14884 $nl = $self->_get_small_int(
279             $i == $len-1 ? $maxt->[-1] + 1 : 256);
280 3460 100       15056 $m0l = $maybe0 ? $max0->[$i] : -1;
281 3460 100       8384 $mtl = $maybebad ? $maxt->[$i] : 256;
282 3460 100       6297 my $lastlimb = $i ? 0 : 1;
283 3460 100 100     24340 if($nl < $m0l + $lastlimb) {
    100          
    100          
284 1628         4328 $self->_put_small_int($m0l + $lastlimb, $nl);
285 1628         9426 return 0;
286             } elsif($nl > $m0l && $nl < $mtl + $lastlimb) {
287 1222         4449 $self->_put_small_int($mtl + $lastlimb - $m0l - 1,
288             $nl - $m0l - 1);
289 1222         7515 return 1;
290             } elsif($nl > $mtl) {
291 30         106 $self->_put_small_int(255 - $mtl, $nl - $mtl - 1);
292 30         624 goto TRY_AGAIN;
293             }
294 580 100       3464 $maybe0 = 0 if $nl > $m0l;
295 580 100       9979 $maybebad = 0 if $nl < $mtl;
296             }
297             }
298              
299             =back
300              
301             =head1 SEE ALSO
302              
303             L,
304             L,
305             L,
306             L,
307             L,
308             L
309              
310             =head1 AUTHOR
311              
312             Andrew Main (Zefram)
313              
314             =head1 COPYRIGHT
315              
316             Copyright (C) 2006, 2007, 2009, 2011
317             Andrew Main (Zefram)
318              
319             =head1 LICENSE
320              
321             This module is free software; you can redistribute it and/or modify it
322             under the same terms as Perl itself.
323              
324             =cut
325              
326             1;