-
Notifications
You must be signed in to change notification settings - Fork 44
/
sp800_22_random_excursion_variant_test.py
78 lines (68 loc) · 2.22 KB
/
sp800_22_random_excursion_variant_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/env python
# sp800_22_random_excursion_variant_test.py
#
# Copyright (C) 2017 David Johnston
# This program is distributed under the terms of the GNU General Public License.
#
# This file is part of sp800_22_tests.
#
# sp800_22_tests is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# sp800_22_tests 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with sp800_22_tests. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import math
# RANDOM EXCURSION VARIANT TEST
def random_excursion_variant_test(bits):
n = len(bits)
x = list() # Convert to +1,-1
for bit in bits:
x.append((bit * 2)-1)
# Build the partial sums
pos = 0
s = list()
for e in x:
pos = pos+e
s.append(pos)
sprime = [0]+s+[0] # Add 0 on each end
# Count the number of cycles J
J = 0
for value in sprime[1:]:
if value == 0:
J += 1
print("J=",J)
# Build the counts of offsets
count = [0 for x in range(-9,10)]
for value in sprime:
if (abs(value) < 10):
count[value] += 1
# Compute P values
success = True
plist = list()
for x in range(-9,10):
if x != 0:
top = abs(count[x]-J)
bottom = math.sqrt(2.0 * J *((4.0*abs(x))-2.0))
p = math.erfc(top/bottom)
plist.append(p)
if p < 0.01:
err = " Not Random"
success = False
else:
err = ""
print("x = %1.0f\t count=%d\tp = %f %s" % (x,count[x],p,err))
if (J < 500):
print("J too small (J=%d < 500) for result to be reliable" % J)
elif success:
print("PASS")
else:
print("FAIL: Data not random")
return (success,None,plist)