Skip to content

Instantly share code, notes, and snippets.

View StuartGordonReid's full-sized avatar

Stuart Gordon Reid StuartGordonReid

View GitHub Profile
@StuartGordonReid
StuartGordonReid / LinearComplexity.py
Last active June 2, 2023 03:10
Python implementation of the linear complexity cryptographic test for randomness. This includes the Berklekamp Massey algorithm.
def linear_complexity(self, bin_data, block_size=500):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this test is the length of a linear feedback shift register (LFSR). The purpose of this test is to
determine whether or not the sequence is complex enough to be considered random. Random sequences are
characterized by longer LFSRs. An LFSR that is too short implies non-randomness.
:param bin_data: a binary string
@StuartGordonReid
StuartGordonReid / Universal.py
Created August 25, 2015 16:03
Python implementation of the Universal cryptographic test for randomness
def universal(self, bin_data: str):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this test is the number of bits between matching patterns (a measure that is related to the
length of a compressed sequence). The purpose of the test is to detect whether or not the sequence can be
significantly compressed without loss of information. A significantly compressible sequence is considered
to be non-random. **This test is always skipped because the requirements on the lengths of the binary
strings are too high i.e. there have not been enough trading days to meet the requirements.
@StuartGordonReid
StuartGordonReid / OverlappingPatterns.py
Created August 25, 2015 16:02
Python implementation of the Overlapping Patterns cryptographic test for randomness
def overlapping_patterns(self, bin_data: str, pattern_size=9, block_size=1032):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of the Overlapping Template Matching test is the number of occurrences of pre-specified target
strings. Both this test and the Non-overlapping Template Matching test of Section 2.7 use an m-bit
window to search for a specific m-bit pattern. As with the test in Section 2.7, if the pattern is not found,
the window slides one bit position. The difference between this test and the test in Section 2.7 is that
when the pattern is found, the window slides only one bit before resuming the search.
@StuartGordonReid
StuartGordonReid / NonOverlappingPatterns.py
Created August 25, 2015 16:01
Python implementation of the Non Overlapping Patterns cryptographic test for randomness
def non_overlapping_patterns(self, bin_data: str, pattern="000000001", num_blocks=8):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this test is the number of occurrences of pre-specified target strings. The purpose of this
test is to detect generators that produce too many occurrences of a given non-periodic (aperiodic) pattern.
For this test and for the Overlapping Template Matching test of Section 2.8, an m-bit window is used to
search for a specific m-bit pattern. If the pattern is not found, the window slides one bit position. If the
pattern is found, the window is reset to the bit after the found pattern, and the search resumes.
@StuartGordonReid
StuartGordonReid / Spectral.py
Created August 25, 2015 16:00
Python implementation of the spectral (discrete Fourier transform) cryptographic tests for randomness
def spectral(self, bin_data: str):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this test is the peak heights in the Discrete Fourier Transform of the sequence. The purpose of
this test is to detect periodic features (i.e., repetitive patterns that are near each other) in the tested
sequence that would indicate a deviation from the assumption of randomness. The intention is to detect whether
the number of peaks exceeding the 95 % threshold is significantly different than 5 %.
@StuartGordonReid
StuartGordonReid / BinaryMatrix.py
Created August 25, 2015 15:59
A Python class for computing the rank of a binary matrix. This is used by the Binary Matrix Rank cryptographic test for randomness
class BinaryMatrix:
def __init__(self, matrix, rows, cols):
"""
This class contains the algorithm specified in the NIST suite for computing the **binary rank** of a matrix.
:param matrix: the matrix we want to compute the rank for
:param rows: the number of rows
:param cols: the number of columns
:return: a BinaryMatrix object
"""
self.M = rows
@StuartGordonReid
StuartGordonReid / BinaryMatrixRank.py
Created August 25, 2015 15:57
Python implementation of the Binary Matrix Rank cryptographic test for randomness
def matrix_rank(self, bin_data: str, q=32):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of the test is the rank of disjoint sub-matrices of the entire sequence. The purpose of this test is
to check for linear dependence among fixed length sub strings of the original sequence. Note that this test
also appears in the DIEHARD battery of tests.
:param bin_data: a binary string
@StuartGordonReid
StuartGordonReid / LongestRuns.py
Created August 25, 2015 15:54
Python implementation of the Longest Runs cryptographic test for randomness
def longest_runs(self, bin_data: str):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of the tests is the longest run of ones within M-bit blocks. The purpose of this tests is to determine
whether the length of the longest run of ones within the tested sequences is consistent with the length of the
longest run of ones that would be expected in a random sequence. Note that an irregularity in the expected
length of the longest run of ones implies that there is also an irregularity ub tge expected length of the long
est run of zeroes. Therefore, only one test is necessary for this statistical tests of randomness
@StuartGordonReid
StuartGordonReid / Runs.py
Created August 25, 2015 15:53
Python implementation of the runs cryptographic test for randomness
def independent_runs(self, bin_data: str):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this tests if the total number of runs in the sequences, where a run is an uninterrupted sequence
of identical bits. A run of length k consists of k identical bits and is bounded before and after with a bit of
the opposite value. The purpose of the runs tests is to determine whether the number of runs of ones and zeros
of various lengths is as expected for a random sequence. In particular, this tests determines whether the
oscillation between zeros and ones is either too fast or too slow.
@StuartGordonReid
StuartGordonReid / BlockFrequency.py
Created August 24, 2015 21:05
Python implementation of the Block Frequency cryptographic test for randomness
def block_frequency(self, bin_data: str, block_size=128):
"""
Note that this description is taken from the NIST documentation [1]
[1] http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this tests is the proportion of ones within M-bit blocks. The purpose of this tests is to determine
whether the frequency of ones in an M-bit block is approximately M/2, as would be expected under an assumption
of randomness. For block size M=1, this test degenerates to the monobit frequency test.
:param bin_data: a binary string