Declan Malone
and 1 contributors

NAME

Crypt::IDA::SlidingWindow - Abstract Sliding Window class

SYNOPSIS

  use Crypt::IDA::SlidingWindow

  my $sw = Crypt::IDA::SlidingWindow->new(
    mode => 'split', rows => 4, window => 16384 );

  # accessors (can also use $sw->{variable} form)
  my $read_head = $sw->read_head;
  my $window    = $sw->window;   #...

  # Testing what can advance
  my ($read_ok, $process_ok, $write_ok, @bundle_ok)
    = $sw->can_advance;
  my $read_ok = $sw->can_fill;
  my $read_ok = $sw->can_fill_substream($row);
  my $process_ok = $sw->process_ok;
  my $write_ok = $sw->can_empty;
  my $write_ok = $sw->can_empty_substream($row);

  # advance pointers after ...
  $sw->advance_read($cols);                # filling input stream
  $sw->advance_read_substream($row,$cols); # filling input substream
  $sw->advance_process($cols);             # processing
  $sw->advance_write($cols);               # emptying output stream
  $sw->advance_write_substream($row,$cols);# emptying output substream

WARNING

This class is not meant to be called directly. Its functionality can be accessed via method calls in Crypt::IDA::Algorithm. It's also possible that it may change in future:

  • the underlying object may change from {} to [] for more efficiency

  • likewise, I might replace it with an XS library

  • the callback feature might change or disappear (moved to Crypt::IDA::Algorithm)

DESCRIPTION

This class implements a Sliding Window algorithm to support cleaner IDA split/combine code. It manages access to the input and output matrix buffers to prevent them from overflowing.

The abstraction assumes that:

  • all pointers refer to matrix columns rather than bytes

  • input and output matrices have the same number of columns

  • pointers are linear (always increasing), rather than circular

  • we're doing IDA-like split/combine operations with one matrix handling a "bundle" of substreams:

    • When splitting, single stream on input, bundle of substreams on output

    • When combining, bundle of substreams on input, single stream on output

The class manages three types of pointer:

  • a 'read' ('fill') pointer tracking input into the input matrix

  • a 'processed' pointer tracking transformation of input into output

  • a 'write' ('empty') pointer tracking data being removed from the output matrix

These should be self-explanatory.

Converting from Linear to Circular Reads/Writes

Internally, all the pointers are linear, but it's possible to convert them to circular pointers within the input or output matrices. Simply:

  • calculate pointer % window_size

  • multiply that value by the size in bytes of a matrix column

This class also provides a convenience method destraddle that takes a pointer and a number of columns to increase it by and checks whether that range would cross the end of the matrix boundary. It returns:

  • the same columns parameter, if the range is contiguous within the matrix

  • two columns values representing contiguous ranges at the end and start of the matrix, respectively, otherwise

For example:

 # Read a row of bytes from a matrix, handling wrap-around
 my ($first,$second) = $sw->destraddle($tail,$cols);
 my $rel_col = $tail % $sw->{window};
 $str = $mat->getvals($row,$rel_col,$first ,$order);
 $str.= $mat->getvals($row,0,       $second,$order) if defined($second);

Substream Bundles

This class maintains an extra set of head and tail pointers for each substream, in addition to the main head/tail pointer. It's assumed that substreams can advance at different rates from each other.

The code for advance_read_substream and advance_write_substream checks whether advancing that substream can advance the parent read/writer, and does so automatically. Callers can check the return value of the method calls, with 1 indicating that the parent pointer advanced.

When the parent pointer advances, it indicates either:

  • when combining, all input substreams got some input, so more processing can be done (providing there is output space)

  • when splitting, all output substreams flushed some share data, so more processing can be done (providing there's more input data).

In the current version of the code, it's also possible to pass a callback to receive notification whenever a bundle of substreams makes progress in this way:

 # when splitting, get callback when all output substreams advance
 $sw->cb_write_bundle(sub {...});
 
 # when splitting, get callback when all input substreams advance
 $sw->cb_read_bundle(sub {...}

This might change in future.

AUTHOR

Declan Malone, <idablack@sourceforge.net>

COPYRIGHT AND LICENSE

Copyright (C) 2019 Declan Malone

This package is free software; you can redistribute it and/or modify it under the terms of version 2 (or, at your discretion, any later version) of the "GNU General Public License" ("GPL").

Please refer to the file "GNU_GPL.txt" in this distribution for details.

DISCLAIMER

This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.