File Coverage

blib/lib/Crypt/IDA.pm
Criterion Covered Total %
statement 398 546 72.8
branch 152 258 58.9
condition 109 237 45.9
subroutine 29 30 96.6
pod 3 16 18.7
total 691 1087 63.5


line stmt bran cond sub pod time code
1             package Crypt::IDA;
2              
3 2     2   30603 use 5.008008;
  2         12  
  2         88  
4 2     2   12 use strict;
  2         4  
  2         69  
5 2     2   11 use warnings;
  2         17  
  2         90  
6              
7 2     2   12 use Carp;
  2         3  
  2         186  
8 2     2   11 use Fcntl qw(:DEFAULT :seek);
  2         5  
  2         1032  
9 2     2   2171 use Math::FastGF2 qw(:ops);
  2         2428  
  2         293  
10 2     2   2015 use Math::FastGF2::Matrix;
  2         40773  
  2         191  
11              
12 2     2   26 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  2         6  
  2         25406  
13              
14             require Exporter;
15              
16             our @export_default = qw(fill_from_string fill_from_fh
17             fill_from_file empty_to_string
18             empty_to_fh empty_to_file
19             ida_split ida_combine);
20             our @export_extras = qw(ida_rng_init ida_fisher_yates_shuffle
21             ida_generate_key ida_check_key
22             ida_key_to_matrix ida_check_transform_opts
23             ida_check_list);
24              
25             our @ISA = qw(Exporter);
26             our %EXPORT_TAGS = ( 'default' => [ @export_default ],
27             'extras' => [ @export_extras ],
28             'all' => [ @export_extras, @export_default ] );
29             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
30             our @EXPORT = qw( );
31              
32             our $VERSION = '0.01';
33              
34             # hard-coding module names is supposedly not good style, but at least
35             # I'm up-front about breaking that "rule":
36             our $classname="Crypt::IDA";
37              
38             sub fill_from_string {
39             # Allow calling as a regular sub call or as a method. This might not
40             # be a good style to use, but it allows callers to use either the
41             # exported name, as in $f=fill_from_string(...) or to avoid
42             # exporting any method names and use the fully-qualified call
43             # $f=Crypt::IDA::fill_from_string(...) without needing to worry
44             # about the extra class name parameter. Of course, this means that
45             # if the user wants to use the class name as the first input
46             # parameter, they'll have to specify it twice. A similar pattern is
47             # used in other routines in this module.
48 16423     16423 0 11375962 my ($self, $class);
49 16423 100 66     79386 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
50 2         4 $self = shift;
51 2   33     13 $class = ref($self) || $self;
52             } else {
53             # we won't actually use the $self->method() style of calling, but
54             # with this pattern we could if we wanted to.
55 16421         19832 $self=$classname;
56 16421         19644 $class=$classname;
57             }
58 16423         26226 my $s = shift;
59 16423   100     47983 my $align = shift || 1;
60              
61             # There's a one-line (non-looping) way of doing the following, but
62             # writing it as a loop is simpler to understand and hence less prone
63             # to errors
64 16423         37258 while ((length $s) % $align) { $s.="\0" }
  21027         39096  
65             return {
66             SUB => sub {
67 34162     34162   44875 my $bytes=shift;
68             # substr returns an empty string if input is empty
69 34162         97182 return substr $s, 0, $bytes, "";
70             }
71 16423         88823 };
72             }
73              
74             sub empty_to_string {
75 24199     24199 1 2416248 my ($self, $class);
76 24199 50 33     113206 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
77 0         0 $self = shift;
78 0   0     0 $class = ref($self) || $self;
79             } else {
80 24199         30514 $self=$classname;
81 24199         31415 $class=$classname;
82             }
83 24199         28899 my $strref=shift;
84              
85             return {
86             SUB => sub {
87 26778     26778   44450 my $str=shift;
88 26778         46023 $$strref.=$str;
89 26778         44503 return length $str;
90             }
91 24199         7397939 };
92             }
93              
94             sub fill_from_fh {
95 15     15 0 16 my ($self, $class);
96 15 50 33     89 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
97 0         0 $self = shift;
98 0   0     0 $class = ref($self) || $self;
99             } else {
100 15         24 $self=$classname;
101 15         17 $class=$classname;
102             }
103 15         19 my $fh=shift;
104 15   100     35 my $align=shift || 0;
105 15   100     42 my $offset=shift || 0;
106 15         18 my $eof=0;
107 15         56 my $bytes_read=0;
108              
109 15 100       34 if ($offset) { sysseek $fh, $offset, SEEK_SET; }
  9         32  
110              
111             return {
112             SUB => sub {
113 34     34   1236 my $bytes = shift;
114 34         45 my $buf = "";
115 34 50       64 if ($bytes < 0) {
116 0         0 carp "Asked to read $bytes bytes\n";
117             }
118 34         242 my $rc = sysread $fh, $buf, $bytes;
119              
120 34 100       81 if ($rc == 0) {
    50          
121 16 100       36 if ($align) {
122 15   100     54 while ($bytes_read % $align and
123             length($buf) < $bytes) {
124 3         4 $buf.="\0";
125 3         12 ++$bytes_read;
126             }
127             }
128             } elsif ($rc < 0) {
129 0         0 return undef;
130             } else {
131 18         21 $bytes_read+=$rc;
132             }
133 34         110 return $buf;
134             }
135 15         400 };
136             }
137              
138             sub fill_from_file {
139 15     15 0 3322 my ($self, $class);
140 15 50 33     91 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
141 0         0 $self = shift;
142 0   0     0 $class = ref($self) || $self;
143             } else {
144 15         27 $self=$classname;
145 15         21 $class=$classname;
146             }
147 15         20 my $filename = shift;
148 15   100     40 my $align = shift || 0;
149 15   100     46 my $offset = shift || 0;
150 15         17 my $fh;
151              
152 15 50       556 return undef unless (sysopen $fh, $filename, O_RDONLY);
153 15         55 return fill_from_fh($fh,$align,$offset);
154             }
155              
156             sub empty_to_fh {
157 12     12 0 16 my ($self, $class);
158 12 100 66     63 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
159 3         6 $self = shift;
160 3   33     15 $class = ref($self) || $self;
161             } else {
162 9         12 $self=$classname;
163 9         11 $class=$classname;
164             }
165 12         15 my $fh = shift;
166 12   100     36 my $offset = shift || 0;
167              
168             #warn "got fh=$fh; offset=$offset\n";
169 12 100       45 sysseek $fh, $offset, SEEK_SET if $offset;
170             return {
171             SUB => sub {
172 12     12   19 my $str=shift;
173 12         355 return syswrite $fh, $str;
174             }
175 12         87 };
176             }
177              
178             sub empty_to_file {
179 3     3 1 4 my ($self, $class);
180 3 50 33     21 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
181 0         0 $self = shift;
182 0   0     0 $class = ref($self) || $self;
183             } else {
184 3         6 $self=$classname;
185 3         21 $class=$classname;
186             }
187 3         6 my $filename = shift;
188 3   50     15 my $perm = shift || 0644;
189 3   50     19 my $offset = shift || 0;
190 3         5 my $fh;
191              
192             return undef unless
193 3 50       306 sysopen $fh, $filename, O_CREAT | O_WRONLY, $perm;
194 3         19 return $self->empty_to_fh($fh, $offset);
195             }
196              
197             # ida_process_streams is the heart of the module. It's called from
198             # both ida_split and ida_combine, so it's capable of operating with
199             # just one or several fillers/emptiers. Its main purpose is to manage
200             # the input/output buffers, and it calls the external matrix multiply
201             # code to actually transform blocks of data in large chunks. For
202             # efficiency, it has some requirements on the organisation of
203             # input/output buffer matrices. It also delegates the task of
204             # reading/writing data to relatively simple user-supplied callbacks.
205             # This module isn't intended to be called by users directly, though,
206             # so it's not even documented in the POD section. Even though
207             # technically this could be useful if the user wanted to specify their
208             # own input/output matrices, there's so little error-checking of
209             # parameters here that it's probably best not to mention its
210             # existence/availability.
211             sub ida_process_streams {
212 6920     6920 0 7840 my ($self, $class);
213 6920 50 33     39920 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
214 0         0 $self = shift;
215 0   0     0 $class = ref($self) || $self;
216             } else {
217 6920         9271 $self=$classname;
218 6920         8002 $class=$classname;
219             }
220 6920         25870 my ($xform, $in, $fillers, $out, $emptiers, $bytes_to_read,
221             $inorder, $outorder)=@_;
222              
223             # default values are no byte-swapping, read bytes until eof
224 6920 50       14605 $inorder=0 unless defined($inorder);
225 6920 50       11443 $outorder=0 unless defined($outorder);
226 6920 50       14108 $bytes_to_read = 0 unless defined($bytes_to_read);
227              
228 6920         8189 my $bytes_read=0;
229 6920         11213 my ($IR, $OW); # input read, output write pointers
230 0         0 my ($ILEN, $OLEN);
231 0         0 my ($IFmin, $OFmax); # input and output buffer fill levels
232 0         0 my ($want_in_size, $want_out_size);
233              
234 0         0 my ($eof, $rc, $str, $max_fill, $max_empty);
235 6920         18067 my $width=$in->WIDTH;
236 6920         7929 my $bits=$width << 3;
237 6920         13478 my $rows=$in->ROWS;
238              
239 6920         8373 my $nfillers = scalar(@$fillers);
240 6920         8263 my $nemptiers = scalar(@$emptiers);
241 6920         17963 my ($idown,$odown);
242 0         0 my ($iright,$oright);
243 0         0 my ($rr,$cc);
244 0         0 my ($i, $k);
245 0         0 my ($start_in_col,$start_out_col);
246              
247             #warn "-------------------------------------\n";
248             #warn "Asked to process $bytes_to_read bytes\n";
249             #warn "Input cols is " .$in->COLS. ", Output cols is " . $out->COLS . "\n";
250             #warn "Inorder is $inorder, Outorder is $outorder\n";
251             #warn "There are $nfillers fillers, $nemptiers emptiers\n";
252              
253 6920 50       23297 if ($bytes_to_read % ($width * $xform->COLS)) {
254 0         0 carp "process_streams: bytes to read not a multiple of COLS * WIDTH";
255 0         0 return undef;
256             }
257 6920 50 66     23096 unless ($nfillers == 1 or $nfillers==$in->ROWS) {
258 0         0 carp "Fillers must be 1 or number of input rows";
259 0         0 return undef;
260             }
261 6920 50 66     24822 unless ($nemptiers == 1 or $nemptiers == $out->ROWS) {
262 0         0 carp "Emptiers must be 1 or number of output rows";
263 0         0 return undef;
264             }
265              
266              
267 6920         13320 ($IFmin, $OFmax, $IR, $OW) = (0,0,0,0);
268 6920 100       16553 if ($nfillers == 1) {
269 4325 50 66     13262 if ($in->ORG ne "colwise" and $in->ROWS != 1) {
270 0         0 carp "Need a 'colwise' input matrix with a single filler";
271 0         0 return undef;
272             }
273 4325         37102 $ILEN=$rows * $in->COLS * $width;
274 4325         5773 $idown=$width;
275 4325         7496 $iright=$in->ROWS * $width;
276 4325         5397 $want_in_size = $width * $rows;
277             } else {
278 2595 50 33     7751 if ($in->ORG ne "rowwise" and $in->ROWS != 1) {
279 0         0 carp "Need a 'rowwise' input matrix with multiple fillers";
280 0         0 return undef;
281             }
282 2595         21823 $ILEN=$in->COLS * $width;
283 2595         4044 $idown=$ILEN;
284 2595         3584 $iright=$width;
285 2595         3370 $want_in_size = $width;
286             }
287 6920         13835 for my $i (0 .. $nfillers - 1) {
288 16430         30113 $fillers->[$i]->{"IW" } = $i * $idown;
289 16430         35251 $fillers->[$i]->{"END"} = $i * $idown + $ILEN - 1;
290 16430         20587 $fillers->[$i]->{"BF"} = 0;
291 16430         33672 $fillers->[$i]->{"PART"} = ""; # partial word
292             }
293 6920 100       16333 if ($nemptiers == 1) {
294 3675 50 66     10943 if ($out->ORG ne "colwise" and $out->ROWS != 1) {
295 0         0 carp "Need a 'colwise' output matrix with a single emptier";
296 0         0 return undef;
297             }
298 3675         33177 $OLEN=$out->ROWS * $out->COLS * $width;
299 3675         5849 $odown=$width;
300 3675         6936 $oright=$out->ROWS * $width;
301 3675         6456 $want_out_size = $width * $out->ROWS;
302             } else {
303 3245 50 33     9578 if ($out->ORG ne "rowwise" and $out->ROWS != 1) {
304 0         0 carp "Need a 'rowwise' output matrix with multiple emptiers";
305 0         0 return undef;
306             }
307 3245         22402 $OLEN = $out->COLS * $width;
308 3245         4128 $odown = $OLEN;
309 3245         4222 $oright = $width;
310 3245         4662 $want_out_size = $width;
311             }
312 6920         13483 for my $i (0 .. $nemptiers - 1) {
313 24210         37932 $emptiers->[$i]->{"OR"} = $i * $odown;
314 24210         37470 $emptiers->[$i]->{"END"} = $i * $odown + $OLEN - 1;
315 24210         30999 $emptiers->[$i]->{"BF"} = 0;
316 24210         42161 $emptiers->[$i]->{"SKIP"} = 0;
317             }
318              
319 6920         10959 do {
320             # fill some of the input matrix
321             #warn "Checking whether we need input (IFmin=$IFmin)\n";
322 14962   100     64940 while (!$eof and ($IFmin < $want_in_size)) {
323             #warn "Seems like we need input\n";
324 14962         33429 for ($i = 0, $IFmin=$ILEN; $i < $nfillers ; ++$i) {
325             #warn "IR is $IR, filler ${i}'s IW is " . $fillers->[$i]->{"IW"}. "\n";
326 34174         55857 $max_fill = $ILEN - $fillers->[$i]->{"BF"};
327 34174 50       74582 if ($fillers->[$i]->{"IW"} >= $IR + $i * $idown) {
328 34174 50       83621 if ($fillers->[$i]->{"IW"} + $max_fill >
329             $fillers->[$i]->{"END"}) {
330 34174         64440 $max_fill = $fillers->[$i]->{"END"} -
331             $fillers->[$i]->{"IW"} + 1;
332             }
333             } else {
334 0 0       0 if ($fillers->[$i]->{"IW"} + $max_fill >=
335             $IR + $i * $idown) {
336 0         0 $max_fill = $IR + $i * $idown - $fillers->[$i]->{"IW"};
337             }
338             }
339              
340             #warn "Before adjusting maxfill: $max_fill (bytes read $bytes_read)\n";
341             #warn "BF on filler $i is ". $fillers->[$i]->{"BF"} . "\n";
342 34174 100 100     101013 if ($bytes_to_read and
343             ($bytes_read + $max_fill > $bytes_to_read)) {
344 12235         14771 $max_fill = $bytes_to_read - $bytes_read;
345             }
346              
347             #next unless $max_fill;
348              
349             #warn "Calling fill handler, maxfill $max_fill\n";
350              
351             # Subtract the length of any bytes from partial word read in
352             # the last time around.
353 34174         52860 $max_fill-=length $fillers->[$i]->{"PART"};
354 34174 50       60121 die "max fill: $max_fill < 0\n" unless $max_fill >= 0;
355              
356 34174         75462 $str=$fillers->[$i]->{"SUB"}->($max_fill);
357              
358             #warn "Got input '$str' on row $i, length ". length($str). "\n";
359              
360 34174 50       99635 if (!defined($str)) {
    100          
361 0         0 carp "Read error on input stream $!";
362 0         0 return undef;
363             } elsif ($str eq "") {
364 16430         20342 ++$eof;
365             } else {
366             # setvals must be passed a string that's aligned to width
367             # (mainly so that it can do byte-order manipulation). As a
368             # result, we need to keep track of any bytes left over from
369             # the last call to the fill handler and prepend them to the
370             # string to be sent to setvals. We also need to chop off any
371             # extra bytes at the end of the string and save them until
372             # the next time around.
373              
374             #warn "Got string '$str' from filler $i\n";
375             #warn "length of str is " . (length($str)) . "\n";
376              
377 17744         35047 my $aligned=$fillers->[$i]->{"PART"} . $str;
378 17744         44609 $fillers->[$i]->{"PART"}=
379             substr $aligned,
380             (length($aligned) - (length($aligned) % $width)),
381             (length($aligned) % $width),
382             "";
383 17744 50       38383 die "Alignment problem with filler $i\n"
384             if length($aligned) % $width;
385 17744 50       35523 die "Alignment problem with fill pointer $i\n"
386             if $fillers->[$i]->{"IW"} % $width;
387              
388             #next unless length $aligned;
389              
390             #warn "Adding string '$aligned' to input buffer\n";
391              
392 17744         68295 $in->
393             setvals($in->
394             offset_to_rowcol($fillers->[$i]->{"IW"}),
395             $aligned,
396             $inorder);
397              
398             # For the purpose of updating IW and BF variables, we
399             # pretend we didn't see any bytes from partial words
400 17744         678574 my $saw_bytes=(length $aligned) - (length($aligned) % $width) ;
401 17744         22911 $bytes_read += $saw_bytes;
402 17744         26912 $fillers->[$i]->{"BF"} += $saw_bytes;
403 17744         21434 $fillers->[$i]->{"IW"} += $saw_bytes;
404 17744 100       45833 if ($fillers->[$i]->{"IW"} > $fillers->[$i]->{"END"}) {
405 7011         11693 $fillers->[$i]->{"IW"} -= $ILEN;
406             }
407             }
408 34174 100       103514 if ($fillers->[$i]->{"BF"} < $IFmin) {
409 11343         30175 $IFmin = $fillers->[$i]->{"BF"};
410             }
411             }
412 14962 100       52311 if ($eof) {
413 6920         1186012 print "EOF detected in $eof stream(s)\n";
414 6920 50       39123 if ($eof % $nfillers) {
415 0         0 carp "Not all input streams of same length";
416 0         0 return undef;
417             }
418             }
419             }
420              
421             # flush some of the output matrix and do some processing
422 14962   66     16492 do {
423              
424             #warn "Checking for output space; OFmax is $OFmax\n";
425              
426             # flush output buffer if we need some space
427 14962   100     78727 while (($eof && $OFmax) || ($OFmax + $want_out_size > $OLEN)) {
      100        
428              
429             #warn "Seems like we needed to flush\n";
430              
431 8042         22376 for ($i=0, $OFmax=0; $i < $nemptiers; ++$i) {
432              
433 26788         46786 $max_empty = $emptiers->[$i]->{"BF"};
434 26788 100       81407 if ($emptiers->[$i]->{"OR"} >= $OW + $i * $odown) {
435 11085 50       35163 if ($emptiers->[$i]->{"BF"} + $want_out_size > $OLEN) {
436 11085         21727 $max_empty = $emptiers->[$i]->{"END"} -
437             $emptiers->[$i]->{"OR"} + 1;
438             #warn "Stopping overflow, max_empty is now $max_empty\n";
439             }
440             } else {
441 15703 50       41055 if ($emptiers->[$i]->{"OR"} + $want_out_size >
442             $OW + $i * $odown) {
443             #warn "Stopping tail overwrite, max_empty is now $max_empty\n";
444 0         0 $max_empty =
445             $OW + $i * $odown - $emptiers->[$i]->{"OR"};
446             # printf ("Stopping tail overwrite, max_empty is now %Ld\n",
447             # (long long) max_fill_or_empty); */
448             }
449             }
450              
451 26788 50 33     115337 die "invalid max empty $max_empty\n"
452             if $max_empty>0 and $max_empty<$width;
453             #next unless $max_empty;
454              
455             # call handler to empty some data
456             #warn "Emptying row $i, col ".
457             # ($emptiers->[$i]->{"OR"} % ( $out->COLS * $width)) .
458             # " with $max_empty bytes\n";
459              
460 26788 50       65236 die "Alignment problem with OR emptier $i" if
461             $emptiers->[$i]->{"OR"} % $width;
462 26788         95773 ($rr,$cc)=$out->
463             offset_to_rowcol($emptiers->[$i]->{"OR"});
464              
465             #warn "got (row,col) ($rr,$cc) from OR#$i offset ".
466             # $emptiers->[$i]->{"OR"}. "\n";
467              
468             # When emptying, we have to check whether the emptier
469             # emptied full words. If it emptied part of a word, we have
470             # to prevent those bytes that were sent from being sent
471             # again. To do this, we keep track of a SKIP variable for
472             # each output buffer, which is the number of bytes to skip
473             # at the start of the output string.
474              
475 26788         450068 $str=$out->
476             getvals($rr,$cc,
477             $max_empty / $width,
478             $outorder);
479             #substr $str, 0, $emptiers->[$i]->{"SKIP"}, "";
480 26788         615122 $rc=$emptiers->[$i]->{"SUB"}->($str);
481              
482 26788 50       55628 unless (defined($rc)) {
483 0         0 carp "ERROR: write error $!\n";
484 0         0 return undef;
485             }
486             #$emptiers->[$i]->{"SKIP"} = $rc % $width;
487             #$rc -= $rc % $width;
488 26788         40769 $emptiers->[$i]->{"BF"} -= $rc;
489 26788         35388 $emptiers->[$i]->{"OR"} += $rc;
490 26788 100       60219 if ($emptiers->[$i]->{"OR"} > $emptiers->[$i]->{"END"}) {
491 11085         19843 $emptiers->[$i]->{"OR"} -= $OLEN;
492             }
493 26788 50       133077 if ($emptiers->[$i]->{"BF"} > $OFmax) {
494 0         0 $OFmax = $emptiers->[$i]->{"BF"};
495             }
496             }
497             }
498              
499             # do some processing
500             #warn "Processing: IR=$IR, OW=$OW, IFmin=$IFmin, OFmax=$OFmax\n";
501 14962         42272 ($rr,$cc)=$in->offset_to_rowcol($IR);
502 14962         1587456 $start_in_col = $cc;
503 14962         44195 ($rr,$cc)=$out->offset_to_rowcol($OW);
504 14962         207486 $start_out_col = $cc;
505 14962         21250 $k=int ($IFmin / $want_in_size);
506             #warn "k=$k, start_in_col=$start_in_col, start_out_col=$start_out_col\n";
507 14962 50       42563 if ($k + $start_in_col > $in->COLS) {
508 0         0 $k = $in->COLS - $start_in_col;
509             }
510 14962 50       42586 if ($k + $start_out_col > $out->COLS) {
511 0         0 $k = $out->COLS - $start_out_col;
512             }
513             #warn "k is now $k\n";
514             Math::FastGF2::Matrix::multiply_submatrix_c
515 14962         59072 ($xform, $in, $out,
516             0, 0, $xform->ROWS,
517             $start_in_col, $start_out_col, $k);
518 14962         19994 $IFmin -= $want_in_size * $k;
519 14962         15691 $OFmax += $want_out_size * $k;
520 14962         15216 $IR+=$iright * $k;
521 14962 100       39870 if ($IR > $fillers->[0]->{"END"}) {
522 3619         5147 $IR=0;
523             }
524 14962         20513 $OW+=$oright * $k;
525 14962 100       31919 if ($OW > $emptiers->[0]->{"END"}) {
526 3619         4295 $OW=0;
527             }
528             # printf ("Moving to next column: IFmin, OFmax are (%lld, %lld)\n",
529             # (long long) IFmin, (long long) OFmax); */
530              
531             #warn "Finished processing chunk of $k columns\n";
532              
533             # we've been updating IFmin and OFmax, but not the real BF
534             # variables in the gf2_streambuf_control structures. We do that
535             # after the processing loop is finished.
536              
537 14962 100       60849 if ($k) {
538 8042         17336 for ($i=0; $i < $nfillers; ++$i) {
539 17744         48149 $fillers->[$i]->{"BF"} -= $k * $want_in_size;
540             }
541 8042         18685 for ($i=0; $i < $nemptiers; ++$i) {
542 26788         82722 $emptiers->[$i]->{"BF"} += $k * $want_out_size;
543             }
544             }
545              
546             } while ($eof && $OFmax);
547             } while (!$eof);
548              
549 6920         52070 return $bytes_read;
550             }
551              
552             sub ida_rng_init {
553 3458     3458 0 58837 my ($self, $class);
554 3458 50 33     16526 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
555 0         0 $self = shift;
556 0   0     0 $class = ref($self) || $self;
557             } else {
558 3458         3917 $self=$classname;
559 3458         4439 $class=$classname;
560             }
561 3458         5766 my $bytes = shift;
562 3458   100     8249 my $source = shift || "/dev/urandom";
563 3458         3304 my $fh;
564              
565 3458 50 100     16330 return undef unless ($bytes == 1 or $bytes == 2 or $bytes == 4);
      66        
566              
567 3458 50       7659 if ($source eq "rand") {
568 0         0 my $max=256 ** $bytes;
569 0     0   0 return sub { int rand $max };
  0         0  
570             }
571              
572 3458 50       222202 return undef unless sysopen $fh, $source, O_RDONLY;
573              
574             # Return an anonymous closure to act as an iterator. Calling the
575             # iterator will return an integer in the range 0 .. 2^(8*bytes)-1
576 3458         6843 my $format;
577 3458 100       10338 if ($bytes == 1) {
    100          
578 1154         1786 $format="C";
579             } elsif ($bytes == 2) {
580 1152         2021 $format="S";
581             } else {
582 1152         2257 $format="L";
583             }
584             return sub {
585 22464     22464   26186 my $deinit=shift; # passing any args will close the
586 22464         26439 my $buf; # file, allowing the calling program
587 22464 50       36825 if (defined($deinit)) { # to deallocate the iterator without
588 0         0 close $fh; # (possibly) leaving an open, but
589 0         0 return undef; # inaccessible file handle
590             }
591 22464 50       151288 if ($bytes != sysread $fh,$buf,$bytes) {
592 0         0 die "Fatal Error: not enough bytes in random source!\n";
593             }
594 22464         47087 return unpack $format, $buf;
595 3458         29345 };
596             };
597              
598             sub ida_fisher_yates_shuffle { # based on recipe 4.15 from the
599             # Perl Cookbook
600 8068     8068 0 48643 my $array=shift;
601              
602             # Note that this uses plain old rand rather than our high-quality
603             # RNG. If that is a problem, either replace this rand with a better
604             # alternative or avoid having this function called by using more
605             # than 1 byte-security. Since we're using the random variables to
606             # generate a permutation, the actual numbers chosen won't be
607             # revealed, so it should be a little more difficult for an attacker
608             # to guess the sequence used (and hence make better guesses about
609             # the random values for the other shares). I can't say either way
610             # whether this will be a problem in practice, but it might be a good
611             # idea to shuffle the array a second time if attacking rand is a
612             # worry. Since an attacker won't have access to all the shares,
613             # this should destroy or limit his ability to determine the order in
614             # which the numbers were generated. Shuffling a list of high-quality
615             # random numbers (such as from the rng_init function) with a
616             # poor-quality rand-based shuffle should not leak any extra
617             # information, while using two passes with the rand-based shuffler
618             # (effectively one to select elements, the other to shuffle them)
619             # seems like it should improve security.
620              
621             # Change recipe to allow picking a certain number of elements
622 8068         10916 my $picks=shift;
623 8068 100 66     44022 $picks=scalar(@$array) unless
      100        
624             defined($picks) and $picks >=0 and $picks
625              
626 8068         10433 my $i=scalar(@$array);
627 8068         18204 while (--$i > $picks - scalar(@$array)) {
628 633756         825445 my $j=int rand ($i + 1); # random int from [0,$i]
629 633756 100       1048231 next if $i==$j; # don't swap element with itself
630 613635         1518604 @$array[$i,$j]=@$array[$j,$i]
631             }
632             # If we want fewer picks than are in the full list, then truncate
633             # the list by shifting off some elements from the front. This
634             # destruction of the list may not be a good thing in general, but
635             # it's fine for our purposes in this program. Note that this tail
636             # processing effectively brings the algorithm up to O(n), where n is
637             # the list length, but we still save out on the more expensive calls
638             # to rand and the element-swapping for elements we'll never
639             # select. Using mjd-permute might be a marginally better choice
640             # where there are many unused elements, but since we're only
641             # interested in using this with arrays of up to 256 elements, this
642             # will be fine.
643             #
644 8068         20146 while (scalar(@$array) > $picks) {
645 291956         488504 shift @$array; # using splice() is quicker!
646             }
647             # splice @$array, 0, scalar @$array - $picks;
648             };
649              
650             sub ida_check_key {
651 1     1 0 2 my ($self, $class);
652 1 50 33     9 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
653 0         0 $self = shift;
654 0   0     0 $class = ref($self) || $self;
655             } else {
656 1         2 $self=$classname;
657 1         3 $class=$classname;
658             }
659 1         3 my ($k,$n,$w,$key)=@_;
660              
661             # Check that key generated by the algorithm (or supplied by the
662             # user) has the properties required for linear independence.
663             #
664             # The key supplied is a list of distinct numbers in the order
665             # x1,...,xn,y1,...,yk
666              
667 1 50       4 die "No key elements to check\n" unless defined $key;
668              
669 1 50       11 die "Supplied key for generating matrix is of the wrong size"
670             unless scalar(@$key) == $k + $n;
671              
672 1         3 my %values;
673              
674             # For integer values xi, yj mod a prime p, the conditons that must
675             # be satisfied are...
676             # xi + yj != 0 |
677             # i != j -> xi != xj } for all i,j
678             # i != j -> yi != yj |
679             #
680             # For calculations in GF_2, since each number is its own additive
681             # inverse, these conditions can be achieved by stating that all
682             # numbers must be distinct.
683 1         4 foreach my $v (@$key) {
684 6 50       61 return 1 if $v >= 256 ** $w;
685 6 50       14 return 1 if exists($values{$v}); # failure; duplicate value
686 6         19 $values{$v}=1;
687             }
688 1         9 return 0; # success; all values distinct
689             };
690              
691             sub ida_generate_key {
692 3458     3458 0 4170 my ($self, $class);
693 3458 50 33     17282 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
694 0         0 $self = shift;
695 0   0     0 $class = ref($self) || $self;
696             } else {
697 3458         5092 $self=$classname;
698 3458         4673 $class=$classname;
699             }
700              
701 3458         6399 my ($k,$n,$w,$rng)=@_;
702 3458         6312 my $key=[];
703              
704             # Generate an array of $k + $n distinct random values, each in the
705             # range [0..256**$w)
706              
707             # If the width is 1 byte, then we'll use the Fisher-Yates shuffle to
708             # choose distinct numbers in the range [0,255]. This takes only
709             # O($k+$n) steps and requires O(256) storage. If the width is 2 or
710             # more bytes, the Fisher-Yates shuffle would require too much memory
711             # (O(2**16), O(2**24), etc.), so we use a different algorithm which
712             # uses the rng to generate the numbers directly, checking for
713             # duplicates as it goes, and re-rolling whenever dups are found.
714 3458 100       6661 if ($w == 1) {
715 1154         311251 push @$key,(0..255);
716 1154         3176 ida_fisher_yates_shuffle($key,$k + $n);
717             } else {
718 2304         2958 my (%rolled,$r);
719 2304         3249 my $count=$k+$n;
720 2304         5122 while ($count) {
721 22464         35778 $r=$rng->();
722 22464 50       48330 next if exists($rolled{$r});
723 22464         42893 $rolled{$r}=1;
724 22464         43885 push @$key,$r;
725 22464         45283 --$count;
726             }
727             }
728              
729             # do a final shuffle of the elements. This should help guard against
730             # exploiting weaknesses in either random generator, but particularly
731             # the 1-byte version which uses the system's rand function. The
732             # extra security derives from the fact that consecutively-generated
733             # numbers will likely end up being distributed to different parties,
734             # so it should no longer be possible for an attacker to determine
735             # the order in which the rng generated them without actually
736             # collecting all the shares (which would avoid the need to attack
737             # the rng in the first place).
738 3458         10298 ida_fisher_yates_shuffle($key);
739 3458         8690 return $key;
740             };
741              
742             sub ida_check_list {
743              
744             # Check a given listref to make sure it has no dups and that all
745             # values are within range. Returns the list less any deleted
746             # elements, as well as doing an in-place delete on the passed
747             # listref.
748              
749 3461     3461 0 6241 my ($list,$item,$min,$max)=@_;
750              
751 3461         6285 my $new_list=[]; # list without dups, invalid values
752 3461         9882 my @saw_val=((0) x $max);
753 3461         7093 for my $i (@$list) {
754 20751 50 33     87843 if ($saw_val[$i]) {
    50          
755 0         0 carp "Duplicate $item number $i in ${item}list; ignoring";
756             } elsif ($i < $min or $i > $max) {
757 0         0 carp "$item number $i out of range in ${item}list; ignoring.";
758             } else {
759 20751         20502 ++$saw_val[$i];
760 20751         37860 push @$new_list, $i;
761             }
762             }
763 3461         11412 $list=$new_list;
764             }
765              
766             sub ida_check_transform_opts {
767              
768             # Return 0 for success, or 1 otherwise. Fixes sharelist if it had
769             # any duplicate or out-of-range vales
770              
771 10381     10381 0 14043 my ($self,$class);
772 10381 50 33     43755 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
773 0         0 $self=shift;
774 0         0 $class=ref($self);
775             } else {
776 10381         14339 $self=$classname;
777             }
778 10381         81877 my %o= (
779             "quorum" => undef,
780             "shares" => undef,
781             "width" => undef,
782             "sharelist" => undef,
783             "key" => undef,
784             "matrix" => undef,
785             @_);
786 62286 50       164924 my ($k,$n,$w,$sharelist,$key,$mat) =
787             map {
788 10381         17441 exists($o{$_}) ? $o{$_} : undef;
789             } qw(quorum shares width sharelist key matrix);
790              
791 10381 50 66     44381 if (defined($key) and defined($mat)) {
792 0         0 carp "both key and matrix parameters supplied; use one only";
793 0         0 return 1;
794             }
795 10381 100       26818 if (defined($key)) {
796 3459 50 33     21841 unless (defined ($n) and defined ($sharelist)) {
797 0         0 carp "If a key is supplied, must specify shares and sharelist";
798 0         0 return 1;
799             }
800 3459 50 33     18277 unless (ref($key) and scalar(@$key) == $k + $n) {
801 0         0 carp "key must be a reference to a list of $k + $n elements";
802 0         0 return 1;
803             }
804             }
805 10381 100       20653 if (defined($mat)) {
806 3465 50       8922 if ( ref($mat) ne "Math::FastGF2::Matrix") {
807 0         0 carp "Matrix must be of type Math::FastGF2::Matrix";
808 0         0 return 1;
809             }
810 3465 50       10741 if ($mat->ORG ne "rowwise") {
811 0         0 carp "supplied matrix must use 'rowwise' organisation";
812 0         0 return undef;
813             }
814 3465 50 33     37412 if (($mat->ROWS != $n or $mat->COLS != $k)) {
815 0         0 carp "supplied matrix must be $n rows x $k cols";
816 0         0 return 1;
817             }
818             }
819 10381 100       19288 if (defined($sharelist)) {
820 3460         11491 ida_check_list($sharelist,"share",0,$n-1);
821 3460 50       8825 unless (scalar(@$sharelist) > 0) {
822 0         0 carp "sharelist does not contain any valid share numbers; aborting";
823 0         0 return 1;
824             }
825             }
826              
827 10381         62322 return 0;
828             }
829              
830             sub ida_key_to_matrix {
831 3458     3458 0 4786 my ($self,$class);
832 3458 50 33     17991 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
833 0         0 $self=shift;
834 0         0 $class=ref($self);
835             } else {
836 3458         5320 $self=$classname;
837             }
838 3458         43043 my %o= (
839             "quorum" => undef,
840             "shares" => undef,
841             "width" => undef,
842             "sharelist" => undef,
843             "key" => undef,
844             "invert?" => 0, # want us to invert the matrix?
845             "skipchecks?" => 0, # skip long checks on options?
846             @_,
847             );
848 24206 50       66446 my ($k,$n,$w,$sharelist,$key,$invert,$skipchecks) =
849             map {
850 3458         6865 exists($o{$_}) ? $o{$_} : undef;
851             } qw(quorum shares width sharelist key invert? skipchecks?);
852              
853             # skip error checking if the caller tells us it's OK
854 3458 50 33     19274 unless (defined($skipchecks) and $skipchecks) {
855 3458 50       14449 if (ida_check_transform_opts(%o)) {
856 0         0 carp "Can't create matrix due to options problem";
857 0         0 return undef;
858             }
859             }
860              
861 3458         37564 my $mat=Math::FastGF2::Matrix ->
862             new(rows => scalar(@$sharelist),
863             cols => $k,
864             width => $w,
865             org => "rowwise");
866 3458 50       111359 unless (defined($mat)) {
867 0         0 carp "Failed to create transform matrix";
868 0         0 return undef;
869             }
870 3458         4171 my $dest_row=0;
871 3458         6399 for my $row (@$sharelist) {
872 20742         32488 for my $col (0 .. $k-1) {
873 97434         109148 my $x = $key->[$row];
874 97434         112366 my $y = $key->[$n+$col];
875 97434         103361 my $sum = $x ^ $y;
876 97434         319041 $mat->setval($dest_row, $col, gf2_inv($w << 3,$sum));
877             }
878 20742         44726 ++$dest_row;
879             }
880 3458 50 33     15018 if (defined($invert) and $invert) {
881 0         0 return $mat->invert;
882             } else {
883 3458         17032 return $mat;
884             }
885             }
886              
887             sub ida_split {
888 3461     3461 0 19437 my ($self, $class);
889 3461 50 33     16410 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
890 0         0 $self = shift;
891 0   0     0 $class = ref($self) || $self;
892             } else {
893 3461         4401 $self=$classname;
894 3461         5556 $class=$classname;
895             }
896 3461         49407 my %o=
897             (
898             quorum => undef,
899             shares => undef,
900             width => undef,
901             # supply either a list of key parameters or a matrix
902             key => undef,
903             matrix => undef,
904             sharelist => undef,
905             # source, sinks
906             filler => undef,
907             emptiers => undef,
908             # misc options
909             rand => "/dev/urandom",
910             bufsize => 4096,
911             bytes => 0,
912             # byte order flags
913             inorder => 0,
914             outorder => 0,
915             @_,
916             );
917              
918             # move all options into local variables
919 44993 50       124776 my ($k,$n,$w,$key,$mat,$sharelist,$filler,$emptiers,$rng,
920             $bufsize,$inorder,$outorder,$bytes_to_read) =
921             map {
922 3461         7299 exists($o{$_}) ? $o{$_} : undef;
923             } qw(quorum shares width key matrix sharelist filler
924             emptiers rand bufsize inorder outorder bytes);
925              
926             # validity checks
927 3461 50 100     21278 unless ($w == 1 or $w == 2 or $w == 4) {
      66        
928 0         0 carp "Width must be one of 1, 2, 4";
929 0         0 return undef;
930             }
931 3461 50 33     18232 unless ($k > 0 and $k < 256 ** $w) {
932 0         0 carp "Quorum value out of range";
933 0         0 return undef;
934             }
935 3461 50 33     17077 unless ($n > 0 and $k + $n < 256 ** $w) {
936 0         0 carp "Number of shares out of range";
937 0         0 return undef;
938             }
939 3461 50       8133 unless (defined ($filler)) {
940 0         0 carp "Need a filler to provide data";
941 0         0 return undef;
942             }
943 3461 50 33     14487 unless (ref($emptiers) and scalar(@$emptiers) == $n) {
944 0         0 carp "emptiers must be a list of $n items (one for each share)";
945 0         0 return undef;
946             }
947 3461 50 33     15380 unless (defined($bufsize) and $bufsize > 0) {
948 0         0 carp "Bad bufsize ($bufsize)";
949 0         0 return undef;
950             }
951 3461 50 33     25170 unless (defined($inorder) and $inorder >= 0 and $inorder <= 2) {
      33        
952 0         0 carp "inorder != 0 (native), 1 (little-endian) or 2 (big-endian)";
953 0         0 return undef;
954             }
955 3461 50 33     24702 unless (defined($outorder) and $outorder >= 0 and $outorder <= 2) {
      33        
956 0         0 carp "outorder != 0 (native), 1 (little-endian) or 2 (big-endian)";
957 0         0 return undef;
958             }
959             # Move some checks to ida_check_transform_opts
960 3461 50       18916 if (ida_check_transform_opts(%o)) {
961 0         0 carp "Can't proceed due to problem with transform options";
962 0         0 return undef;
963             }
964              
965 3461 50 33     18687 if (defined($bytes_to_read) and $bytes_to_read < 0) {
966 0         0 carp "bytes parameter must be 0 (read until eof) or greater";
967 0         0 return undef;
968             }
969              
970 3461 100       6738 if (defined($sharelist)) {
971              
972             # moved some checks to ida_check_transform_opts
973              
974 1 50       6 if (defined($mat)) {
975             # copy only the listed rows into a new matrix
976 1         9 my $m2=Math::FastGF2::Matrix->new(rows => scalar(@$sharelist),
977             cols => $k,
978             width => $w,
979             org => "rowwise");
980 1 50       38 unless (defined($m2)) {
981 0         0 carp "Problem creating submatrix with rows from sharelist";
982 0         0 return undef;
983             }
984 1         2 my $dest_row=0;
985 1         3 for my $row (@$sharelist) {
986 3         9 for my $col (0 .. $k-1) {
987 9         35 $m2->setval($dest_row,$col, $mat->getval($row,$col));
988             }
989 3         7 ++$dest_row;
990             }
991 1         3 $mat=$m2; # replace matrix with reduced one
992             }
993             } else {
994 3460         12448 $sharelist=[0..$n-1];
995             }
996              
997 3461 100       8668 unless (defined($mat)) {
998 3456 50       7215 if (defined ($key)) {
999 0 0       0 if (ida_check_key($k,$n,$w,$key)) {
1000 0         0 carp "Problem with supplied key";
1001 0         0 return undef;
1002             }
1003             } else {
1004             # no key and no matrix, so generate random key
1005 3456         8926 $rng=ida_rng_init($w,$rng);
1006 3456 50       7345 unless (defined($rng)) {
1007 0         0 carp "Failed to initialise random number generator";
1008 0         0 return undef;
1009             }
1010 3456         8561 $key=ida_generate_key($k,$n,$w,$rng);
1011             }
1012              
1013             # now generate matrix from key
1014 3456         12413 $mat=ida_key_to_matrix( "quorum" => $k,
1015             "shares" => $n,
1016             "width" => $w,
1017             "sharelist" => $sharelist,
1018             "key" => $key,
1019             "skipchecks?" => 0);
1020             }
1021              
1022             # create the buffer matrices and start the transform
1023 3461         14132 my $in = Math::FastGF2::Matrix->new(rows=>$k,
1024             cols=>$bufsize,
1025             width=>$w,
1026             org => "colwise");
1027 3461         106313 my $out= Math::FastGF2::Matrix->new(rows=>scalar(@$sharelist),
1028             cols=>$bufsize,
1029             width=>$w,
1030             org => "rowwise");
1031 3461 50 33     103684 unless (defined($in) and defined($out)) {
1032 0         0 carp "failed to allocate input/output buffer matrices";
1033 0         0 return undef;
1034             }
1035 3461         13315 my $rc=ida_process_streams($mat,
1036             $in, [$filler],
1037             $out, $emptiers,
1038             $bytes_to_read,
1039             $inorder, $outorder);
1040 3461 50       8815 if (defined ($rc)) {
1041 3461         149118 return ($key,$mat,$rc);
1042             } else {
1043 0         0 return undef;
1044             }
1045             }
1046              
1047             sub ida_combine {
1048 3459     3459 1 19066 my $self;
1049             my $class;
1050 3459 50 33     19726 if ($_[0] eq $classname or ref($_[0]) eq $classname) {
1051 0         0 $self = shift;
1052 0   0     0 $class = ref($self) || $self;
1053             } else {
1054 3459         4228 $self=$classname;
1055 3459         4616 $class=$classname;
1056             }
1057 3459         50546 my %o=
1058             (
1059             quorum => undef,
1060             shares => undef, # only needed if key supplied
1061             width => undef,
1062             # supply either a list of key parameters and a list of keys or a
1063             # pre-inverted matrix generated from those key details
1064             key => undef,
1065             matrix => undef,
1066             sharelist => undef,
1067             # source, sinks
1068             fillers => undef,
1069             emptier => undef,
1070             # misc options
1071             bufsize => 4096,
1072             bytes => 0,
1073             # byte order flags
1074             inorder => 0,
1075             outorder => 0,
1076             @_,
1077             );
1078              
1079             # copy all options into local variables
1080 41508 50       117939 my ($k,$n,$w,$key,$mat,$sharelist,$fillers,$emptier,
1081             $bufsize,$inorder,$outorder,$bytes_to_read) =
1082             map {
1083 3459         8206 exists($o{$_}) ? $o{$_} : undef;
1084             } qw(quorum shares width key matrix sharelist fillers
1085             emptier bufsize inorder outorder bytes);
1086              
1087             # validity checks
1088 3459 50 100     23986 unless ($w == 1 or $w == 2 or $w == 4) {
      66        
1089 0         0 carp "Width must be one of 1, 2, 4";
1090 0         0 return undef;
1091             }
1092 3459 50 33     19254 unless ($k > 0 and $k < 256 ** $w) {
1093 0         0 carp "Quorum value out of range";
1094 0         0 return undef;
1095             }
1096 3459 50 33     17337 unless (ref($fillers) and scalar(@$fillers) == $k) {
1097 0         0 carp "fillers must be a list of $k items (one for each share)";
1098 0         0 return undef;
1099             }
1100 3459 50       9156 unless (defined($emptier)) {
1101 0         0 carp "need an emptier to write data to";
1102 0         0 return undef;
1103             }
1104 3459 50 33     14828 unless (defined($bufsize) and $bufsize > 0) {
1105 0         0 carp "Bad bufsize";
1106 0         0 return undef;
1107             }
1108 3459 50 33     21033 unless (defined($inorder) and $inorder >= 0 and $inorder <= 2) {
      33        
1109 0         0 carp "inorder ($inorder) != 0 (native), ".
1110             "1 (little-endian) or 2 (big-endian)";
1111 0         0 return undef;
1112             }
1113 3459 50 33     20693 unless (defined($outorder) and $outorder >= 0 and $outorder <= 2) {
      33        
1114 0         0 carp "outorder ($outorder) != 0 (native), ".
1115             "1 (little-endian) or 2 (big-endian)";
1116 0         0 return undef;
1117             }
1118 3459 50       6468 if (defined($key)) {
1119 0 0       0 if (ida_check_key($k,$n,$w,$key)) {
1120 0         0 carp "Invalid key supplied";
1121 0         0 return undef;
1122             }
1123             } else {
1124 3459         8725 $o{"shares"}=$k; # needed for ida_check_transform_opts
1125 3459         5012 $n=$k;
1126             }
1127 3459 50       19822 if (ida_check_transform_opts(%o)) {
1128 0         0 carp "Can't continue due to problem with transform opts";
1129 0         0 return undef;
1130             }
1131 3459 50 33     18303 if (defined($bytes_to_read) and $bytes_to_read < 0) {
1132 0         0 carp "bytes parameter must be 0 (read until eof) or greater";
1133 0         0 return undef;
1134             }
1135              
1136 3459 50       6844 if (defined($key)) {
1137 0         0 ida_check_list($sharelist,"share",0,$k-1);
1138 0 0       0 unless (scalar(@$sharelist) == $k) {
1139 0         0 carp "sharelist does not have k=$k elements";
1140 0         0 return undef;
1141             }
1142             #warn "Creating and inverting matrix from key\n";
1143 0         0 $mat=ida_key_to_matrix(%o, "skipchecks?" => 0, "invert?" => 1);
1144 0 0       0 unless (defined($mat)) {
1145 0         0 carp "Failed to invert transform matrix (this shouldn't happen)";
1146 0         0 return undef;
1147             }
1148             }
1149              
1150             # create the buffer matrices and start the transform
1151 3459         21071 my $in = Math::FastGF2::Matrix->new(rows=>$k,
1152             cols=>$bufsize,
1153             width=>$w,
1154             org => "rowwise");
1155 3459         104036 my $out= Math::FastGF2::Matrix->new(rows=>$k,
1156             cols=>$bufsize,
1157             width=>$w,
1158             org => "colwise");
1159 3459 50 33     115615 unless (defined($in) and defined($out)) {
1160 0         0 carp "failed to allocate input/output buffer matrices";
1161 0         0 return undef;
1162             }
1163 3459         12777 my @vals=$mat->getvals(0,0,$k * $n);
1164             #warn "matrix is [" . (join ", ", map
1165             # {sprintf("%02x",$_) } @vals) . "] (" .
1166             # scalar(@vals) . " values)\n";
1167              
1168 3459         3279985 return ida_process_streams($mat,
1169             $in, $fillers,
1170             $out, [$emptier],
1171             $bytes_to_read,
1172             $inorder, $outorder);
1173              
1174             }
1175              
1176              
1177             1;
1178             __END__