Research source · python
c7_base_compiler.py
site/public/research-artifacts/c7-compiler-review/c7_base_compiler.py
404 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: dd936aedbe4e37431c276b1e83669684aece2d5460332337f206efb2721a2bc4
#!/usr/bin/env python3
"""Exact audit of the Polak--Schrijver/Gao C7^5 base gadget.
The construction deliberately does not contain the 367 codewords as data.
It regenerates the 327-word circular core, the 71-vertex extension graph, and
the unique 40-word patch selected by Gao's typed gadget constraints.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from collections import Counter
from functools import lru_cache
from pathlib import Path
Q = 7
DIMENSION = 5
MODULUS = 382
SHIFT = (40, 123, 40, 123, 40)
OLD_COMPANION_POINT = (2, 4, 6, 3, 5)
NEW_COMPANION_POINT = (1, 5, 6, 3, 5)
PAIRS = (
((1, 3, 4, 4, 6), (2, 3, 5, 4, 6)),
((3, 4, 0, 3, 5), (2, 4, 6, 3, 5)),
((5, 3, 1, 3, 4), (5, 3, 2, 3, 5)),
((4, 4, 6, 1, 6), (5, 4, 6, 0, 6)),
((6, 0, 6, 4, 5), (6, 1, 6, 5, 5)),
((0, 3, 5, 6, 5), (6, 3, 5, 0, 5)),
((6, 4, 3, 4, 0), (6, 4, 2, 4, 6)),
((6, 4, 5, 3, 2), (6, 5, 5, 3, 1)),
)
J0 = frozenset((0, 5, 6))
Word = tuple[int, int, int, int, int]
def closed_confusable(left: Word, right: Word) -> bool:
return all((x - y) % Q in (0, 1, Q - 1) for x, y in zip(left, right))
def independent(points: set[Word] | frozenset[Word]) -> bool:
ordered = sorted(points)
return all(
not closed_confusable(left, right)
for index, left in enumerate(ordered)
for right in ordered[index + 1 :]
)
def transform_t(word: Word) -> Word:
return (
(2 - word[1]) % Q,
word[3],
word[0],
(2 - word[2]) % Q,
word[4],
)
def quantize(value: int) -> int:
# floor(value / 54.5), written without floating point.
return (2 * value) // 109
def all_words() -> list[Word]:
return [
tuple((number // (Q ** (DIMENSION - 1 - position))) % Q for position in range(DIMENSION)) # type: ignore[misc]
for number in range(Q**DIMENSION)
]
def circular_precursor_image() -> list[Word]:
return [
tuple(
quantize((t * pow(7, position, MODULUS) + SHIFT[position]) % MODULUS)
for position in range(DIMENSION)
) # type: ignore[misc]
for t in range(MODULUS)
]
def circular_core() -> tuple[set[Word], list[Word]]:
image = circular_precursor_image()
if len(set(image)) != MODULUS:
raise AssertionError("quantized precursor is not injective")
bad = {
left
for left in image
if any(left != right and closed_confusable(left, right) for right in image)
}
core = set(image) - bad
if len(core) != 327 or len(bad) != 55 or not independent(core):
raise AssertionError("unexpected circular-core counts")
return core, image
def extension_graph(core: set[Word]) -> tuple[list[Word], list[int]]:
vertices = [
word
for word in all_words()
if word not in core
and all(not closed_confusable(word, base) for base in core)
]
adjacency = [0] * len(vertices)
for i, left in enumerate(vertices):
for j in range(i + 1, len(vertices)):
if closed_confusable(left, vertices[j]):
adjacency[i] |= 1 << j
adjacency[j] |= 1 << i
if len(vertices) != 71 or sum(mask.bit_count() for mask in adjacency) // 2 != 85:
raise AssertionError("unexpected extension graph")
return vertices, adjacency
def typed_patch(core: set[Word], vertices: list[Word], adjacency: list[int]) -> tuple[set[Word], int, dict[str, int]]:
index = {word: i for i, word in enumerate(vertices)}
phase_h = {
PAIRS[i][0] if i in J0 else PAIRS[i][1]
for i in range(len(PAIRS))
}
phase_v = {
PAIRS[i][1] if i in J0 else PAIRS[i][0]
for i in range(len(PAIRS))
}
endpoints = phase_h | phase_v
if not independent(phase_h) or not independent(phase_v):
raise AssertionError("a transversal is not independent")
def category(point: Word) -> str:
hit_h = any(closed_confusable(point, endpoint) for endpoint in phase_h)
hit_v = any(closed_confusable(point, endpoint) for endpoint in phase_v)
if hit_h and hit_v:
return "HV"
if hit_h:
return "H"
if hit_v:
return "V"
return "O"
preimages = [word for word in core if transform_t(word) == OLD_COMPANION_POINT]
if preimages != [(6, 0, 6, 4, 5)]:
raise AssertionError("unexpected companion replacement preimage")
replacement_preimage = preimages[0]
fixed_companion = {transform_t(word) for word in core}
fixed_companion.remove(OLD_COMPANION_POINT)
fixed_companion.add(NEW_COMPANION_POINT)
fixed_profile = Counter(category(word) for word in fixed_companion)
if fixed_profile != Counter({"O": 292, "H": 19, "V": 16}):
raise AssertionError("unexpected fixed companion profile")
quotas = {"O": 29, "H": 7, "V": 4}
forced_words = {center for center, _ in PAIRS if center in index}
forced_mask = sum(1 << index[word] for word in forced_words)
forbidden_mask = 0
for word_index, word in enumerate(vertices):
forbidden = False
# Each alternative may see only its designated center in the code.
for center, alternative in PAIRS:
if word != center and closed_confusable(alternative, word):
forbidden = True
transformed = transform_t(word)
# T(code), after the one stated replacement, must remain an independent
# auxiliary set disjoint from all endpoints and from the forbidden HV cell.
if closed_confusable(transformed, NEW_COMPANION_POINT):
forbidden = True
if transformed in endpoints or category(transformed) == "HV":
forbidden = True
if forbidden:
forbidden_mask |= 1 << word_index
if forced_mask & forbidden_mask:
raise AssertionError("typed constraints forbid a required center")
for i in range(len(vertices)):
if forced_mask >> i & 1:
forbidden_mask |= adjacency[i]
if forced_mask & forbidden_mask:
raise AssertionError("required centers conflict")
forced_counts = Counter(
category(transform_t(vertices[i]))
for i in range(len(vertices))
if forced_mask >> i & 1
)
remaining_quota = tuple(
quotas[name] - forced_counts[name]
for name in ("O", "H", "V")
)
available_mask = ((1 << len(vertices)) - 1) & ~forbidden_mask & ~forced_mask
category_index = {
"O": 0,
"H": 1,
"V": 2,
}
category_masks = [0, 0, 0]
for i, word in enumerate(vertices):
name = category(transform_t(word))
if name in category_index:
category_masks[category_index[name]] |= 1 << i
search_nodes = 0
@lru_cache(maxsize=None)
def count_solutions(mask: int, need_o: int, need_h: int, need_v: int) -> tuple[int, int]:
"""Return (solution count capped at two, one solution mask)."""
nonlocal search_nodes
search_nodes += 1
needs = (need_o, need_h, need_v)
if any(need < 0 for need in needs):
return 0, 0
for category_number, need in enumerate(needs):
if (mask & category_masks[category_number]).bit_count() < need:
return 0, 0
if sum(needs) == 0:
return 1, 0
if mask.bit_count() < sum(needs):
return 0, 0
# Branch on a high-degree live vertex; this makes the finite uniqueness
# proof small while leaving the logic transparent and dependency-free.
live = [i for i in range(len(vertices)) if mask >> i & 1]
vertex = max(live, key=lambda i: (adjacency[i] & mask).bit_count())
bit = 1 << vertex
count_without, witness_without = count_solutions(
mask & ~bit, need_o, need_h, need_v
)
name = category(transform_t(vertices[vertex]))
category_number = category_index[name]
next_needs = [need_o, need_h, need_v]
next_needs[category_number] -= 1
count_with, witness_with = count_solutions(
mask & ~bit & ~adjacency[vertex], *next_needs
)
if count_with:
witness_with |= bit
total = min(2, count_without + count_with)
witness = witness_without if count_without else witness_with
return total, witness
solution_count, solution_mask = count_solutions(available_mask, *remaining_quota)
if solution_count != 1:
raise AssertionError(f"typed patch is not unique: capped count {solution_count}")
patch_mask = forced_mask | solution_mask
patch = {
vertices[i]
for i in range(len(vertices))
if patch_mask >> i & 1
}
if len(patch) != 40 or not independent(patch):
raise AssertionError("typed patch is not a 40-word independent set")
code = core | patch
for center, alternative in PAIRS:
hits = {word for word in code if closed_confusable(alternative, word)}
if hits != {center}:
raise AssertionError("private-pair condition failed")
companion = {transform_t(word) for word in code}
companion.remove(OLD_COMPANION_POINT)
companion.add(NEW_COMPANION_POINT)
profile = Counter(category(word) for word in companion)
if len(companion) != 367 or not independent(companion):
raise AssertionError("companion is not a 367-word independent set")
if profile != Counter({"O": 321, "H": 26, "V": 20}):
raise AssertionError("typed profile failed")
if companion & endpoints:
raise AssertionError("companion meets a pair endpoint")
return patch, search_nodes, dict(profile)
def minimal_block_dfa(code: set[Word]) -> dict[str, object]:
"""Build the exact right-residual quotient for code* with block length five."""
layer_residuals: list[set[frozenset[tuple[int, ...]]]] = []
for depth in range(DIMENSION):
prefixes = {word[:depth] for word in code}
residuals = {
frozenset(word[depth:] for word in code if word[:depth] == prefix)
for prefix in prefixes
}
layer_residuals.append(residuals)
states = {
(depth, residual): number
for number, (depth, residual) in enumerate(
(depth, residual)
for depth, residuals in enumerate(layer_residuals)
for residual in residuals
)
}
root_residual = next(iter(layer_residuals[0]))
root = states[(0, root_residual)]
transitions: list[tuple[int, int, int]] = []
for depth, residuals in enumerate(layer_residuals):
for residual in residuals:
source = states[(depth, residual)]
letters = {suffix[0] for suffix in residual}
for letter in letters:
successors = frozenset(
suffix[1:] for suffix in residual if suffix[0] == letter
)
if depth == DIMENSION - 1:
target = root
else:
target = states[(depth + 1, successors)]
transitions.append((source, letter, target))
incoming = Counter((letter, target) for _, letter, target in transitions)
return {
"partial_states": len(states),
"complete_states_with_dead": len(states) + 1,
"transitions": len(transitions),
"layer_residual_counts": [len(residuals) for residuals in layer_residuals],
"reversible": all(count == 1 for count in incoming.values()),
"reversibility_collision_keys": sum(count > 1 for count in incoming.values()),
"maximum_same_label_indegree": max(incoming.values()),
}
def canonical_hash(code: set[Word]) -> str:
payload = "\n".join("".join(map(str, word)) for word in sorted(code)) + "\n"
return hashlib.sha256(payload.encode("ascii")).hexdigest()
def parse_reference(path: Path) -> set[Word]:
return {
tuple(map(int, line.split())) # type: ignore[misc]
for line in path.read_text(encoding="utf-8").splitlines()
if line.strip()
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--reference-r367", type=Path)
parser.add_argument("--output", type=Path)
args = parser.parse_args()
core, precursor_image = circular_core()
vertices, adjacency = extension_graph(core)
patch, search_nodes, profile = typed_patch(core, vertices, adjacency)
code = core | patch
if len(code) != 367 or not independent(code):
raise AssertionError("generated code is not an independent 367-set")
# The untyped extension graph does not select Gao's patch: replacing the
# fifth center by its private alternative gives a second 40-set.
published_center, private_alternative = PAIRS[5]
alternative_patch = (patch - {published_center}) | {private_alternative}
if len(alternative_patch) != 40 or not independent(alternative_patch):
raise AssertionError("expected alternative 40-set is not independent")
reference_matches = None
if args.reference_r367:
reference = parse_reference(args.reference_r367)
reference_matches = reference == code
if not reference_matches:
raise AssertionError("generated code differs from the published R367 input")
result = {
"schema": "fprd.c7-typed-patch-attack.v1",
"status": "pass",
"precursor_words": len(precursor_image),
"precursor_distinct_words": len(set(precursor_image)),
"discarded_conflicting_words": len(set(precursor_image) - core),
"circular_core_words": len(core),
"extension_vertices": len(vertices),
"extension_edges": sum(mask.bit_count() for mask in adjacency) // 2,
"typed_patch_words": len(patch),
"typed_patch_unique": True,
"typed_uniqueness_search_nodes": search_nodes,
"untyped_patch_not_unique": True,
"untyped_one_swap": {
"remove": published_center,
"add": private_alternative,
},
"code_words": len(code),
"code_independent": True,
"companion_profile": profile,
"canonical_code_sha256": canonical_hash(code),
"minimal_exact_block_dfa": minimal_block_dfa(code),
"last_signature_state_lower_bound": 1 + len(code),
"reference_matches": reference_matches,
}
rendered = json.dumps(result, indent=2, sort_keys=True) + "\n"
if args.output:
args.output.write_text(rendered, encoding="utf-8")
print(rendered, end="")
if __name__ == "__main__":
main()