The UML Class diagrams (Infrastructure, Algorithms, Functional Decomposition and AlgorithmExecs) below illustrate the design principles of the Cryptography-Study.
An instance of an
AlgorithmExec
class controls the execution of an Algorithm
class.
Both AlgorithmExec
and Algorithm
inherit from the trait Tracing
.
The trait Tracing
provides a control structure, namely withTracer()
which uses the
Tracer
instance given by getCurrentTracer()
. By default this method returns a
NullTracer
which traces nothing. Several algorithm classes override this method to trace their calculations.
Algorithm classes which need not any further revision may simply remove the overridden method.
The execution of an Algorithm
object proceeds by (1) providing a description of the algorithm (optional), (2) by reading the input parameter,
(3) by instantiating an Algorithm
object with the given parameter and requesting its outcome
,
(4) by crosschecking the result and last but not least by providing the outcome or an error message.
That is, the execution of an algorithm is widely decoupled from its internal computations.
By exploiting this, the BatchExecutor
creates and processes several specialised AlgorithmExec
instances by parsing a XML batch file. Following the completion
of these AlgorithmExec
instances, another XML file will be produced which contains the results of the program run.
The Algorithm
class comes with two template arguments. The first template argument U
is a placeholder for the input type of the algorithm and the second one stands for the output type. Furthermore concrete Algorithm
classes must provide
an implementation of the abstract calculate(): V
method. Clients call this method not directly but may initiate
the computation by requesting the lazily evaluated outcome: V
value. Optionally Algorithm
may
override the crossCheck(): Boolean
method to verify the result of the calculation.
Now consider the class hierarchy below the DLAlgorithm class (see diagram Algorithms). Among the concrete
classes EnumerationAlgo
, PollardRho
and BabyStepGiantStep
the simple EnumerationAlgo
has with O(n) by far the worst runtime complexity.
The PohligHellmanAlgo
needs one of these basic algorithms to compute the discrete logarithms within the
subgroups. My implementation uses a bounded
template argument to specify the type of an internal field used for this purpose. Therefore we have three incarnations of concrete
PohligHellmanAlgo
s.
The diagram Functional Decomposition gives an overview on which actual algorithms
PohligHellmanWithPollardRho
and PohligHellmanWithBSGS
are relying on.