Fixes, tests passing.
This commit is contained in:
+26
-35
@@ -1,44 +1,12 @@
|
||||
from secrets import randbelow, token_bytes
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher
|
||||
from cryptography.hazmat.primitives.ciphers.algorithms import ChaCha20
|
||||
from scipy.stats import chisquare
|
||||
|
||||
from randquik import cha
|
||||
|
||||
|
||||
def test_cha_generate_statistical():
|
||||
"""Requests in multiple of ChaCha20 block size 64 bytes"""
|
||||
ROUNDS = 100
|
||||
min_p = 1 - 0.99 ** (1 / ROUNDS) # 99 % confidence over the entire test
|
||||
print(min_p)
|
||||
|
||||
for round in range(ROUNDS):
|
||||
# First round both zero, use 8-byte nonce as round counter
|
||||
key = bytes(32)
|
||||
nonce = round.to_bytes(8, "little")
|
||||
iv = bytes(8) + nonce # Cryptography module requires IV (counter, nonce)
|
||||
# Varying sizes to test internal processing that occurs in 64 bit blocks
|
||||
# and with SIMD implementations also 256 or 512 bytes at a time.
|
||||
N = 10000 + randbelow(10000)
|
||||
ct0, ct1 = bytearray(N), bytearray(N)
|
||||
Cipher(ChaCha20(key, iv), None, None).encryptor().update_into(bytes(N), ct0)
|
||||
cha.generate(ct1, key, nonce)
|
||||
assert len(ct0) == len(ct1)
|
||||
assert ct0.hex() == ct1.hex()
|
||||
assert ct1.count(0)
|
||||
|
||||
# Zeroing out 50 bytes fail the test in ~30 rounds
|
||||
# ct1[:50] = bytes(50)
|
||||
|
||||
# Test that all byte values are equivalently common (despite zero inputs)
|
||||
observed = np.bincount(ct1, minlength=256)
|
||||
expected = np.full(256, N / 256)
|
||||
chi2, p_value = chisquare(observed, expected)
|
||||
assert p_value >= min_p, f"{round=} {N=}"
|
||||
|
||||
|
||||
def test_cipherstreams_fullblocks():
|
||||
"""Requests in multiple of ChaCha20 block size 64 bytes"""
|
||||
key = token_bytes(32)
|
||||
@@ -51,7 +19,30 @@ def test_cipherstreams_fullblocks():
|
||||
ct0 = c0.update(bytes(N))
|
||||
ct1 = c1(bytearray(N))
|
||||
assert len(ct0) == len(ct1)
|
||||
assert ct0.hex() == ct1.hex()
|
||||
assert ct0.hex() == ct1.hex(), f"{i=} {N=}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"counter",
|
||||
[
|
||||
b"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
b"\xFF\xFF\xFF\xFF\x00\x00\x00\x00",
|
||||
b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
|
||||
b"\xFF\xFF\xFF\x7F\xFF\xFF\xFF\xFF",
|
||||
b"\x00\x00\x00\x80\xFF\xFF\xFF\xFF",
|
||||
],
|
||||
)
|
||||
def test_counter_wrap(counter):
|
||||
"""Tests carry handling of counter increments"""
|
||||
key = bytes(32)
|
||||
iv = counter + b"--------"
|
||||
c0 = Cipher(ChaCha20(key, iv), None, None).encryptor()
|
||||
c1 = cha.Cha(key, iv)
|
||||
N = 128
|
||||
ct0 = c0.update(bytes(N))
|
||||
ct1 = c1(bytearray(N))
|
||||
assert len(ct0) == len(ct1)
|
||||
assert ct0.hex() == ct1.hex()
|
||||
|
||||
|
||||
def test_cipherstreams_partial_updates():
|
||||
@@ -66,7 +57,7 @@ def test_cipherstreams_partial_updates():
|
||||
ct0 = c0.update(bytes(N))
|
||||
ct1 = c1(bytearray(N))
|
||||
assert len(ct0) == len(ct1)
|
||||
assert ct0.hex() == ct1.hex()
|
||||
assert ct0.hex() == ct1.hex(), f"{i=} {N=}"
|
||||
|
||||
|
||||
def test_cipherstreams_32leftover():
|
||||
|
||||
Reference in New Issue
Block a user