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__ |