Skip to content

Instantly share code, notes, and snippets.

@rhizoome
Created January 5, 2018 14:22
Show Gist options
  • Save rhizoome/ef5d38415ee6cecd666455e07d78e8bb to your computer and use it in GitHub Desktop.
Save rhizoome/ef5d38415ee6cecd666455e07d78e8bb to your computer and use it in GitHub Desktop.
Check if crc32 and md5 are affine
"""Affinity test."""
from hashlib import md5
from binascii import crc32
from hypothesis import given
from hypothesis.strategies import integers, lists, tuples
# In practice, CRC operations are often started with a nonzero state. Because
# of this, the actual equation is usually of the form:
# crc(a)⊕crc(b)=crc(a⊕b)⊕c
# for some constant c (which depends on the length of a, b).
# An alternative way of expressing this is, for three any equal-length
# bitstrings a,b,ca,b,c, we have:
# crc(a)⊕crc(b)⊕crc(c)=crc(a⊕b⊕c)
# The technical term for this relationship is affine; in cryptography, we treat
# it as linear because, for attacks that assume linearity, affine works just as
# well.
_bin32 = integers(min_value=0, max_value=2**32 - 1)
def crc32i(a):
"""crc32 an integer."""
return crc32(a.to_bytes(4, "big"))
def md532i(a):
"""md5 corresponding to the crc32i, to prove it is not affine."""
d = md5(a.to_bytes(4, "big")).digest()
return int.from_bytes(d[:4], "big", signed=True)
@given(lists(tuples(_bin32, _bin32), min_size=10))
def test_crc_not_affine(data):
"""If crc32 is affine as described above this should fail."""
cl = map(lambda v: crc32i(v[0]) ^ crc32i(v[1]) ^ crc32i(v[0] ^ v[1]), data)
# Check if c is constant
x = next(cl)
assert all(c == x for c in cl)
@given(lists(tuples(_bin32, _bin32), min_size=10))
def test_md5_not_affine(data):
"""If crc32 is affine as described above this should fail."""
cl = map(lambda v: md532i(v[0]) ^ md532i(v[1]) ^ md532i(v[0] ^ v[1]), data)
# Check if c is constant
x = next(cl)
assert all(c == x for c in cl)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment