File Coverage

blib/lib/Ordeal/Model/ChaCha20.pm
Criterion Covered Total %
statement 236 279 84.5
branch 8 18 44.4
condition 2 3 66.6
subroutine 22 26 84.6
pod 6 6 100.0
total 274 332 82.5


line stmt bran cond sub pod time code
1             package Ordeal::Model::ChaCha20;
2              
3             # vim: ts=3 sts=3 sw=3 et ai :
4              
5             # Adapted from Math::Prime::Util::ChaCha 0.70
6             # https://metacpan.org/pod/Math::Prime::Util::ChaCha
7             # which is copyright 2017 by Dana Jacobsen E<lt>dana@acm.orgE<gt>
8              
9 6     6   113 use 5.020;
  6         23  
10 6     6   35 use strict;
  6         12  
  6         122  
11 6     6   29 use warnings;
  6         12  
  6         288  
12             { our $VERSION = '0.004'; }
13 6     6   36 use Ouch;
  6         12  
  6         35  
14 6     6   423 use Mo qw< build default >;
  6         13  
  6         49  
15 6     6   6510 use experimental qw< signatures postderef >;
  6         7010  
  6         37  
16 6     6   1031 no warnings qw< experimental::signatures experimental::postderef >;
  6         13  
  6         240  
17              
18 6     6   39 use constant BITS => (~0 == 4294967295) ? 32 : 64;
  6         19  
  6         400  
19 6     6   33 use constant CACHE_SIZE => 1000;
  6         14  
  6         284  
20 6     6   47 use constant ROUNDS => 20;
  6         38  
  6         414  
21              
22 6     6   38 use constant RELEASE => 0x01; # 0x00 marks extension
  6         9  
  6         10101  
23              
24             has _state => ();
25             has _buffer => ();
26             has seed => ();
27              
28 15     15   18 sub _bits_rand ($self, $n) {
  15         20  
  15         26  
  15         20  
29 15         38 while (length($self->{_buffer}) < $n) {
30 3         14 my $add_on = $self->_core((int($n / 8) + 64) >> 6);
31 3         23 $self->{_buffer} .= unpack 'b*', $add_on;
32             }
33 15         43 return substr $self->{_buffer}, 0, $n, '';
34             } ## end sub _bits_rand
35              
36 3     3 1 125 sub BUILD ($self) {
  3         6  
  3         5  
37 3   66     9 my $seed = $self->seed // do {
38 1         48 my $s = CORE::rand 1_000_000;
39 1 50       13 $s < 4294967295
40             ? pack 'V', $s
41             : pack 'V2', $s, $s >> 32;
42             };
43 3         24 $self->seed($seed);
44 3         16 $self->reset;
45             } ## end sub BUILD ($self)
46              
47 0     0 1 0 sub clone ($self) { return ref($self)->new->restore($self->freeze) }
  0         0  
  0         0  
  0         0  
48              
49 0     0 1 0 sub freeze ($self) {
  0         0  
  0         0  
50 0         0 my $release = unpack 'H*', pack 'C*', RELEASE;
51 0         0 my $state = unpack 'H*', join '', pack 'N*', $self->_state->@*;
52 0         0 my $buffer = $self->_buffer;
53 0         0 my $buflen = unpack 'H*', pack 'N', length $buffer;
54 0         0 $buffer = unpack 'H*', join '', pack 'B*', $buffer;
55 0         0 my $seed = unpack 'H*', substr $self->seed, 0, 40;
56 0         0 return join '', $release, $state, $buflen, $buffer, $seed;
57             }
58              
59 13     13   20 sub _int_rand_parameters ($self, $N) {
  13         19  
  13         16  
  13         15  
60 13         19 state $cache = {};
61 13 50       26 return $cache->{$N}->@* if exists $cache->{$N};
62              
63             # basic parameters, find the minimum number of bits to cover $N
64 13         35 my $nbits = int(log($N) / log(2));
65 13         21 my $M = 2 ** $nbits;
66 13         27 while ($M < $N) {
67 6         9 $nbits++;
68 6         11 $M *= 2;
69             }
70 13         25 my $reject_threshold = $M - $M % $N; # same as $N here
71              
72             # if there is still space in the cache, this pair will be used many
73             # times, so we want to reduce the rejection rate
74 13 50       28 if (keys($cache->%*) <= CACHE_SIZE) {
75              
76             # The average number of rolls needed to get a non-rejected sample
77             # is the inverse of the acceptance probability:
78             #
79             # $P = $rejected_threshold/$M
80             #
81             # This means that, on average, we will need $nbits * 1 / $P bits for
82             # each successful roll. If this goes beyond $nbits + 1, we might just
83             # as well draw one more bit in the first place and get a non-worse
84             # rejection rate.
85 13         30 while (($nbits * $M / $reject_threshold) > ($nbits + 1)) {
86 3         5 $nbits++;
87 3         3 $M *= 2;
88 3         8 $reject_threshold = $M - $M % $N;
89             }
90             }
91 13         31 return ($nbits, $reject_threshold);
92             }
93              
94 13     13 1 23 sub int_rand ($self, $low, $high) {
  13         15  
  13         16  
  13         18  
  13         17  
95 13         21 my $N = $high - $low + 1;
96 13         29 my ($nbits, $reject_threshold) = $self->_int_rand_parameters($N);
97 13         22 my $retval = $reject_threshold;
98 13         23 while ($retval >= $reject_threshold) {
99 15         30 my $bitsequence = $self->_bits_rand($nbits);
100 15         24 $retval = 0;
101 15         49 for my $v (reverse split //, pack 'b*', $bitsequence) {
102 13         22 $retval <<= 8;
103 13         34 $retval += ord $v;
104             }
105             } ## end while ($retval >= $reject_threshold)
106 13         30 return $low + $retval % $N;
107             } ## end sub int_rand
108              
109 3     3 1 7 sub reset ($self) {
  3         8  
  3         5  
110 3         7 my $seed = $self->seed;
111 3         21 $seed .= pack 'C', 0 while length($seed) % 4;
112 3         18 my @seed = unpack 'V*', substr $seed, 0, 40;
113 3 50       9 if (@seed < 10) {
114 3 100       7 my $rng = __prng_new(map { $_ <= $#seed ? $seed[$_] : 0 } 0 .. 3);
  12         45  
115 3         10 push @seed, __prng_next($rng) while @seed < 10;
116             }
117 3 50       10 ouch 500, 'seed count failure', @seed if @seed != 10;
118 3         27 $self->_state(
119             [
120             0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, # 1^ row
121             @seed[0 .. 3], # 2^ row
122             @seed[4 .. 7], # 3^ row
123             0, 0, @seed[8 .. 9], # 4^ row
124             ]
125             );
126 3         16 $self->_buffer('');
127             }
128              
129 0     0   0 sub _restore_01 ($self, $opaque) {
  0         0  
  0         0  
  0         0  
130 0         0 for ($opaque) {
131 0         0 my @state = unpack 'N*', join '', pack 'H*', substr $_, 0, 128, '';
132 0         0 $self->_state(\@state);
133 0         0 s{^-}{}mxs;
134 0         0 my $buflen = unpack 'N', pack 'H*', substr $_, 0, 8, '';
135 0         0 s{^-}{}mxs;
136 0         0 my $buffer = '';
137 0 0       0 if ($buflen) {
138 0         0 my $sl = ($buflen + (8 - $buflen % 8) % 8) / 4; # 2 * ... / 8
139 0         0 $buffer = unpack 'B*', join '', pack 'H*', substr $_, 0, $sl, '';
140 0         0 $buffer = substr $buffer, 0, $buflen;
141             }
142 0         0 $self->_buffer($buffer);
143 0         0 s{^-}{}mxs;
144 0         0 $self->seed(join '', pack 'H*', $_);
145             }
146 0         0 return $self;
147             }
148              
149 0     0 1 0 sub restore ($self, $opaque) {
  0         0  
  0         0  
  0         0  
150 0         0 my $release = substr $opaque, 0, 2, '';
151 0 0       0 my $method = $self->can("_restore_$release")
152             or ouch 400, 'cannot restore release', $release;
153 0         0 $self->$method($opaque);
154 0         0 return $self;
155             }
156              
157             # Simple PRNG used to fill small seeds
158 37     37   48 sub __prng_next ($s) {
  37         45  
  37         41  
159 37         50 my $word;
160 37         47 my $oldstate = $s->[0];
161 37         49 if (BITS == 64) {
162 37         57 $s->[0] = ($s->[0] * 747796405 + $s->[1]) & 0xFFFFFFFF;
163 37         59 $word =
164             ((($oldstate >> (($oldstate >> 28) + 4)) ^ $oldstate) * 277803737)
165             & 0xFFFFFFFF;
166             } ## end if (BITS == 64)
167             else {
168             {
169 6     6   3454 use integer;
  6         90  
  6         46  
170             $s->[0] = unpack("L", pack("L", $s->[0] * 747796405 + $s->[1]));
171             }
172             $word =
173             (($oldstate >> (($oldstate >> 28) + 4)) ^ $oldstate) & 0xFFFFFFFF;
174 6     6   449 { use integer; $word = unpack("L", pack("L", $word * 277803737)); }
  6         64  
  6         23  
175             } ## end else [ if (BITS == 64) ]
176 37         79 ($word >> 22) ^ $word;
177             } ## end sub __prng_next ($s)
178              
179 3     3   5 sub __prng_new ($A, $B, $C, $D) {
  3         6  
  3         3  
  3         4  
  3         5  
  3         5  
180 3         10 my @s = (0, (($B << 1) | 1) & 0xFFFFFFFF);
181 3         11 __prng_next(\@s);
182 3         7 $s[0] = ($s[0] + $A) & 0xFFFFFFFF;
183 3         7 __prng_next(\@s);
184 3         5 $s[0] = ($s[0] ^ $C) & 0xFFFFFFFF;
185 3         10 __prng_next(\@s);
186 3         6 $s[0] = ($s[0] ^ $D) & 0xFFFFFFFF;
187 3         9 __prng_next(\@s);
188 3         6 return \@s;
189             } ## end sub __prng_new
190              
191             ###############################################################################
192             # Begin ChaCha core, reference RFC 7539
193             # with change to make blockcount/nonce be 64/64 from 32/96
194             # Dana Jacobsen, 9 Apr 2017
195             # Adapted Flavio Poletti, 3 Feb 2018
196              
197             # State is:
198             # cccccccc cccccccc cccccccc cccccccc
199             # kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
200             # kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
201             # bbbbbbbb nnnnnnnn nnnnnnnn nnnnnnnn
202             #
203             # c=constant k=key b=blockcount n=nonce
204              
205             # We have to take care with 32-bit Perl so it sticks with integers.
206             # Unfortunately the pragma "use integer" means signed integer so
207             # it ruins right shifts. We also must ensure we save as unsigned.
208              
209 3     3   6 sub _core ($self, $blocks) {
  3         4  
  3         5  
  3         5  
210 3         7 my $j = $self->_state;
211 3         13 my $ks = '';
212              
213 3         8 while ($blocks-- > 0) {
214             my (
215 3         10 $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7,
216             $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15
217             ) = @$j;
218 3         9 for (1 .. ROUNDS / 2) {
219 6     6   1986 use integer;
  6         14  
  6         21  
220 30         39 if (BITS == 64) {
221 30         42 $x0 = ($x0 + $x4) & 0xFFFFFFFF;
222 30         37 $x12 ^= $x0;
223 30         44 $x12 = (($x12 << 16) | ($x12 >> 16)) & 0xFFFFFFFF;
224 30         39 $x8 = ($x8 + $x12) & 0xFFFFFFFF;
225 30         39 $x4 ^= $x8;
226 30         40 $x4 = (($x4 << 12) | ($x4 >> 20)) & 0xFFFFFFFF;
227 30         40 $x0 = ($x0 + $x4) & 0xFFFFFFFF;
228 30         41 $x12 ^= $x0;
229 30         40 $x12 = (($x12 << 8) | ($x12 >> 24)) & 0xFFFFFFFF;
230 30         41 $x8 = ($x8 + $x12) & 0xFFFFFFFF;
231 30         37 $x4 ^= $x8;
232 30         49 $x4 = (($x4 << 7) | ($x4 >> 25)) & 0xFFFFFFFF;
233 30         42 $x1 = ($x1 + $x5) & 0xFFFFFFFF;
234 30         37 $x13 ^= $x1;
235 30         42 $x13 = (($x13 << 16) | ($x13 >> 16)) & 0xFFFFFFFF;
236 30         54 $x9 = ($x9 + $x13) & 0xFFFFFFFF;
237 30         40 $x5 ^= $x9;
238 30         40 $x5 = (($x5 << 12) | ($x5 >> 20)) & 0xFFFFFFFF;
239 30         41 $x1 = ($x1 + $x5) & 0xFFFFFFFF;
240 30         51 $x13 ^= $x1;
241 30         42 $x13 = (($x13 << 8) | ($x13 >> 24)) & 0xFFFFFFFF;
242 30         41 $x9 = ($x9 + $x13) & 0xFFFFFFFF;
243 30         40 $x5 ^= $x9;
244 30         41 $x5 = (($x5 << 7) | ($x5 >> 25)) & 0xFFFFFFFF;
245 30         39 $x2 = ($x2 + $x6) & 0xFFFFFFFF;
246 30         38 $x14 ^= $x2;
247 30         40 $x14 = (($x14 << 16) | ($x14 >> 16)) & 0xFFFFFFFF;
248 30         40 $x10 = ($x10 + $x14) & 0xFFFFFFFF;
249 30         37 $x6 ^= $x10;
250 30         45 $x6 = (($x6 << 12) | ($x6 >> 20)) & 0xFFFFFFFF;
251 30         37 $x2 = ($x2 + $x6) & 0xFFFFFFFF;
252 30         40 $x14 ^= $x2;
253 30         43 $x14 = (($x14 << 8) | ($x14 >> 24)) & 0xFFFFFFFF;
254 30         38 $x10 = ($x10 + $x14) & 0xFFFFFFFF;
255 30         38 $x6 ^= $x10;
256 30         45 $x6 = (($x6 << 7) | ($x6 >> 25)) & 0xFFFFFFFF;
257 30         39 $x3 = ($x3 + $x7) & 0xFFFFFFFF;
258 30         39 $x15 ^= $x3;
259 30         43 $x15 = (($x15 << 16) | ($x15 >> 16)) & 0xFFFFFFFF;
260 30         42 $x11 = ($x11 + $x15) & 0xFFFFFFFF;
261 30         36 $x7 ^= $x11;
262 30         39 $x7 = (($x7 << 12) | ($x7 >> 20)) & 0xFFFFFFFF;
263 30         41 $x3 = ($x3 + $x7) & 0xFFFFFFFF;
264 30         39 $x15 ^= $x3;
265 30         40 $x15 = (($x15 << 8) | ($x15 >> 24)) & 0xFFFFFFFF;
266 30         41 $x11 = ($x11 + $x15) & 0xFFFFFFFF;
267 30         37 $x7 ^= $x11;
268 30         44 $x7 = (($x7 << 7) | ($x7 >> 25)) & 0xFFFFFFFF;
269 30         39 $x0 = ($x0 + $x5) & 0xFFFFFFFF;
270 30         37 $x15 ^= $x0;
271 30         44 $x15 = (($x15 << 16) | ($x15 >> 16)) & 0xFFFFFFFF;
272 30         40 $x10 = ($x10 + $x15) & 0xFFFFFFFF;
273 30         38 $x5 ^= $x10;
274 30         47 $x5 = (($x5 << 12) | ($x5 >> 20)) & 0xFFFFFFFF;
275 30         36 $x0 = ($x0 + $x5) & 0xFFFFFFFF;
276 30         38 $x15 ^= $x0;
277 30         54 $x15 = (($x15 << 8) | ($x15 >> 24)) & 0xFFFFFFFF;
278 30         37 $x10 = ($x10 + $x15) & 0xFFFFFFFF;
279 30         37 $x5 ^= $x10;
280 30         45 $x5 = (($x5 << 7) | ($x5 >> 25)) & 0xFFFFFFFF;
281 30         38 $x1 = ($x1 + $x6) & 0xFFFFFFFF;
282 30         36 $x12 ^= $x1;
283 30         45 $x12 = (($x12 << 16) | ($x12 >> 16)) & 0xFFFFFFFF;
284 30         40 $x11 = ($x11 + $x12) & 0xFFFFFFFF;
285 30         36 $x6 ^= $x11;
286 30         39 $x6 = (($x6 << 12) | ($x6 >> 20)) & 0xFFFFFFFF;
287 30         41 $x1 = ($x1 + $x6) & 0xFFFFFFFF;
288 30         35 $x12 ^= $x1;
289 30         55 $x12 = (($x12 << 8) | ($x12 >> 24)) & 0xFFFFFFFF;
290 30         45 $x11 = ($x11 + $x12) & 0xFFFFFFFF;
291 30         43 $x6 ^= $x11;
292 30         40 $x6 = (($x6 << 7) | ($x6 >> 25)) & 0xFFFFFFFF;
293 30         38 $x2 = ($x2 + $x7) & 0xFFFFFFFF;
294 30         44 $x13 ^= $x2;
295 30         39 $x13 = (($x13 << 16) | ($x13 >> 16)) & 0xFFFFFFFF;
296 30         39 $x8 = ($x8 + $x13) & 0xFFFFFFFF;
297 30         35 $x7 ^= $x8;
298 30         46 $x7 = (($x7 << 12) | ($x7 >> 20)) & 0xFFFFFFFF;
299 30         41 $x2 = ($x2 + $x7) & 0xFFFFFFFF;
300 30         36 $x13 ^= $x2;
301 30         50 $x13 = (($x13 << 8) | ($x13 >> 24)) & 0xFFFFFFFF;
302 30         34 $x8 = ($x8 + $x13) & 0xFFFFFFFF;
303 30         38 $x7 ^= $x8;
304 30         45 $x7 = (($x7 << 7) | ($x7 >> 25)) & 0xFFFFFFFF;
305 30         36 $x3 = ($x3 + $x4) & 0xFFFFFFFF;
306 30         35 $x14 ^= $x3;
307 30         45 $x14 = (($x14 << 16) | ($x14 >> 16)) & 0xFFFFFFFF;
308 30         40 $x9 = ($x9 + $x14) & 0xFFFFFFFF;
309 30         35 $x4 ^= $x9;
310 30         41 $x4 = (($x4 << 12) | ($x4 >> 20)) & 0xFFFFFFFF;
311 30         41 $x3 = ($x3 + $x4) & 0xFFFFFFFF;
312 30         35 $x14 ^= $x3;
313 30         42 $x14 = (($x14 << 8) | ($x14 >> 24)) & 0xFFFFFFFF;
314 30         51 $x9 = ($x9 + $x14) & 0xFFFFFFFF;
315 30         39 $x4 ^= $x9;
316 30         64 $x4 = (($x4 << 7) | ($x4 >> 25)) & 0xFFFFFFFF;
317             } ## end if (BITS == 64)
318             else { # 32-bit
319             $x0 += $x4;
320             $x12 ^= $x0;
321             $x12 = ($x12 << 16) | (($x12 >> 16) & 0xFFFF);
322             $x8 += $x12;
323             $x4 ^= $x8;
324             $x4 = ($x4 << 12) | (($x4 >> 20) & 0xFFF);
325             $x0 += $x4;
326             $x12 ^= $x0;
327             $x12 = ($x12 << 8) | (($x12 >> 24) & 0xFF);
328             $x8 += $x12;
329             $x4 ^= $x8;
330             $x4 = ($x4 << 7) | (($x4 >> 25) & 0x7F);
331             $x1 += $x5;
332             $x13 ^= $x1;
333             $x13 = ($x13 << 16) | (($x13 >> 16) & 0xFFFF);
334             $x9 += $x13;
335             $x5 ^= $x9;
336             $x5 = ($x5 << 12) | (($x5 >> 20) & 0xFFF);
337             $x1 += $x5;
338             $x13 ^= $x1;
339             $x13 = ($x13 << 8) | (($x13 >> 24) & 0xFF);
340             $x9 += $x13;
341             $x5 ^= $x9;
342             $x5 = ($x5 << 7) | (($x5 >> 25) & 0x7F);
343             $x2 += $x6;
344             $x14 ^= $x2;
345             $x14 = ($x14 << 16) | (($x14 >> 16) & 0xFFFF);
346             $x10 += $x14;
347             $x6 ^= $x10;
348             $x6 = ($x6 << 12) | (($x6 >> 20) & 0xFFF);
349             $x2 += $x6;
350             $x14 ^= $x2;
351             $x14 = ($x14 << 8) | (($x14 >> 24) & 0xFF);
352             $x10 += $x14;
353             $x6 ^= $x10;
354             $x6 = ($x6 << 7) | (($x6 >> 25) & 0x7F);
355             $x3 += $x7;
356             $x15 ^= $x3;
357             $x15 = ($x15 << 16) | (($x15 >> 16) & 0xFFFF);
358             $x11 += $x15;
359             $x7 ^= $x11;
360             $x7 = ($x7 << 12) | (($x7 >> 20) & 0xFFF);
361             $x3 += $x7;
362             $x15 ^= $x3;
363             $x15 = ($x15 << 8) | (($x15 >> 24) & 0xFF);
364             $x11 += $x15;
365             $x7 ^= $x11;
366             $x7 = ($x7 << 7) | (($x7 >> 25) & 0x7F);
367             $x0 += $x5;
368             $x15 ^= $x0;
369             $x15 = ($x15 << 16) | (($x15 >> 16) & 0xFFFF);
370             $x10 += $x15;
371             $x5 ^= $x10;
372             $x5 = ($x5 << 12) | (($x5 >> 20) & 0xFFF);
373             $x0 += $x5;
374             $x15 ^= $x0;
375             $x15 = ($x15 << 8) | (($x15 >> 24) & 0xFF);
376             $x10 += $x15;
377             $x5 ^= $x10;
378             $x5 = ($x5 << 7) | (($x5 >> 25) & 0x7F);
379             $x1 += $x6;
380             $x12 ^= $x1;
381             $x12 = ($x12 << 16) | (($x12 >> 16) & 0xFFFF);
382             $x11 += $x12;
383             $x6 ^= $x11;
384             $x6 = ($x6 << 12) | (($x6 >> 20) & 0xFFF);
385             $x1 += $x6;
386             $x12 ^= $x1;
387             $x12 = ($x12 << 8) | (($x12 >> 24) & 0xFF);
388             $x11 += $x12;
389             $x6 ^= $x11;
390             $x6 = ($x6 << 7) | (($x6 >> 25) & 0x7F);
391             $x2 += $x7;
392             $x13 ^= $x2;
393             $x13 = ($x13 << 16) | (($x13 >> 16) & 0xFFFF);
394             $x8 += $x13;
395             $x7 ^= $x8;
396             $x7 = ($x7 << 12) | (($x7 >> 20) & 0xFFF);
397             $x2 += $x7;
398             $x13 ^= $x2;
399             $x13 = ($x13 << 8) | (($x13 >> 24) & 0xFF);
400             $x8 += $x13;
401             $x7 ^= $x8;
402             $x7 = ($x7 << 7) | (($x7 >> 25) & 0x7F);
403             $x3 += $x4;
404             $x14 ^= $x3;
405             $x14 = ($x14 << 16) | (($x14 >> 16) & 0xFFFF);
406             $x9 += $x14;
407             $x4 ^= $x9;
408             $x4 = ($x4 << 12) | (($x4 >> 20) & 0xFFF);
409             $x3 += $x4;
410             $x14 ^= $x3;
411             $x14 = ($x14 << 8) | (($x14 >> 24) & 0xFF);
412             $x9 += $x14;
413             $x4 ^= $x9;
414             $x4 = ($x4 << 7) | (($x4 >> 25) & 0x7F);
415             } ## end else [ if (BITS == 64) ]
416             } ## end for (1 .. ROUNDS / 2)
417 3         30 $ks .= pack("V16",
418             $x0 + $j->[0],
419             $x1 + $j->[1],
420             $x2 + $j->[2],
421             $x3 + $j->[3],
422             $x4 + $j->[4],
423             $x5 + $j->[5],
424             $x6 + $j->[6],
425             $x7 + $j->[7],
426             $x8 + $j->[8],
427             $x9 + $j->[9],
428             $x10 + $j->[10],
429             $x11 + $j->[11],
430             $x12 + $j->[12],
431             $x13 + $j->[13],
432             $x14 + $j->[14],
433             $x15 + $j->[15]);
434 3 50       15 if (++$j->[12] > 4294967295) {
435 0         0 $j->[12] = 0;
436 0         0 $j->[13]++;
437             }
438             } ## end while ($blocks-- > 0)
439 3         7 return $ks;
440             } ## end sub _core
441              
442             # End ChaCha core
443             ###############################################################################
444              
445             1;
446             __END__