Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion research/t74-low-alias-width-cap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ python3 -I -B research/t74-low-alias-width-cap/check_export.py
```

Expected: `PASS_T74_LOW_ALIAS_WIDTH_CAP 1687/1000000 patterns 1163 ... rejecting_controls 8`
and `PASS_T74_WIDTH_CAP_EXPORT controls 4`.
and `PASS_T74_WIDTH_CAP_EXPORT controls 8`.

The package also registers its commands for the repository replay hook:

Expand Down Expand Up @@ -152,6 +152,17 @@ stock/precision contract is established here. The cap concerns the primitive
recurrence b; applying it to an outer κ requires that outer construction's
inherited b-to-κ relationship.

The arithmetic loader executes the exact source bytes checked against
`INPUTS.json`, without consulting Python bytecode caches. `-B` alone suppresses
cache writes but still permits cache reads. Four export controls install
conflicting timestamp or unchecked-hash caches and replay in both normal and
optimized mode; every run must retain the original receipt and leave the export
unchanged. This repairs the same source/cache distinction identified in the
related [PR2766](https://github.com/CrocSwap/integer-mult-bounds/pull/2766).
[PR2553](https://github.com/CrocSwap/integer-mult-bounds/pull/2553) isolates the
registered runner's cache namespace; this fix also covers direct verifier calls.
The arithmetic source, inputs, dual and expected mathematical receipt are unchanged.

## Open next questions

1. **Can an anticipatory alias keep its lender narrow?** The 32 low aliases
Expand Down
2 changes: 1 addition & 1 deletion research/t74-low-alias-width-cap/VERIFY.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"{package}/check_export.py"
],
"timeout_seconds": 60,
"checks": "Standalone read-only export, no-clobber, input and receipt tamper rejection."
"checks": "Standalone read-only export, no-clobber, input and receipt tamper rejection. Four source/bytecode binding controls: timestamp and unchecked-hash caches under normal and optimized Python."
}
]
}
41 changes: 40 additions & 1 deletion research/t74-low-alias-width-cap/check_export.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/usr/bin/env python3
"""Verify source-only read-only replay, evidence binding and no-clobber."""
import importlib.util
import py_compile
import struct
import hashlib
import json
from pathlib import Path
Expand All @@ -26,6 +29,40 @@ def replay(root, *args):
cwd=root.parent, capture_output=True, text=True, timeout=30)


def check_bytecode_caches(root):
"""Cached code must not replace the authenticated arithmetic source."""
source = root / 'vendor/fine_moment.py'
original = source.read_bytes()
stamp = source.stat()
cache_dir = source.parent / '__pycache__'
# This root is a new source-only export: no existing cache may be removed.
need(not cache_dir.exists(), 'unexpected cache in fresh export')
with tempfile.TemporaryDirectory(prefix='t74-cache-control-') as tmp:
wrong_source = Path(tmp) / 'wrong.py'
wrong_source.write_text("raise RuntimeError('UNAUTHENTICATED_BYTECODE_EXECUTED')\n")
for mode in (py_compile.PycInvalidationMode.TIMESTAMP,
py_compile.PycInvalidationMode.UNCHECKED_HASH):
for optimized in (False, True):
cache = Path(importlib.util.cache_from_source(
str(source), optimization='1' if optimized else ''))
cache.parent.mkdir(exist_ok=True)
py_compile.compile(str(wrong_source), cfile=str(cache), dfile=str(source),
doraise=True, optimize=int(optimized), invalidation_mode=mode)
if mode == py_compile.PycInvalidationMode.TIMESTAMP:
data = bytearray(cache.read_bytes())
data[8:16] = struct.pack('<II', int(stamp.st_mtime) & 0xffffffff,
stamp.st_size & 0xffffffff)
cache.write_bytes(data)
before = snapshot(root)
command = [sys.executable, '-I'] + (['-O'] if optimized else [])
result = subprocess.run(command + ['-B', str(root / 'verify.py')],
cwd=root.parent, capture_output=True, text=True, timeout=30)
need(result.returncode == 0, 'cached code replaced pinned source: ' + result.stderr)
need(snapshot(root) == before, 'cache control changed source or cached bytes')
need(source.read_bytes() == original, 'cache control changed pinned source')
shutil.rmtree(cache_dir)


def main():
with tempfile.TemporaryDirectory(prefix='t74-width-cap-') as temp:
dst = Path(temp)/'standalone'
Expand All @@ -45,6 +82,8 @@ def main():
result = replay(dst, '--record', dst/'EXPECTED.json')
need(result.returncode != 0 and 'receipt already exists' in result.stderr, 'overwrite accepted')
need(snapshot(dst) == before, 'overwrite changed receipt')
check_bytecode_caches(dst)
need(snapshot(dst) == before, 'bytecode controls changed export')
source = dst/'inputs/pr2269-profile.json'
old = source.read_bytes(); source.write_bytes(old+b' ')
result = replay(dst)
Expand All @@ -55,7 +94,7 @@ def main():
receipt.write_text(json.dumps(changed))
result = replay(dst)
need(result.returncode != 0 and 'receipt mismatch' in result.stderr, 'altered expected result accepted')
print('PASS_T74_WIDTH_CAP_EXPORT controls 4')
print('PASS_T74_WIDTH_CAP_EXPORT controls 8')


if __name__ == '__main__':
Expand Down
9 changes: 6 additions & 3 deletions research/t74-low-alias-width-cap/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,11 @@ def geometry(plan):
return dict(sorted(stock.items()))


def power_engine():
def power_engine(source_bytes):
spec = importlib.util.spec_from_file_location('width_cap_moment', ROOT/'vendor/fine_moment.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Execute the bytes authenticated by run(), never an unrelated .pyc cache.
exec(compile(source_bytes, str(ROOT/'vendor/fine_moment.py'), 'exec'), module.__dict__)
# Same directed algorithm and explicit tails; this coarse bound needs no
# 3000-digit endpoint. Integer fallback suffices in the standard library.
module.SH = 256
Expand Down Expand Up @@ -199,9 +200,11 @@ def rejected(label, action):

def run():
pins = read(ROOT/'INPUTS.json')
verified = {}
for entry in pins['sources']:
data = (ROOT/entry['path']).read_bytes()
need(hashlib.sha256(data).hexdigest() == entry['sha256'], 'source digest: '+entry['path'])
verified[entry['path']] = data
if 'uncompressed_sha256' in entry:
need(hashlib.sha256(gzip.decompress(data)).hexdigest() == entry['uncompressed_sha256'], 'uncompressed digest')
extra = read(ROOT/'inputs/word80-extra.json.gz')
Expand All @@ -214,7 +217,7 @@ def run():
plan = read(ROOT/'inputs/pr2269-plan.json.gz')
stock = geometry(plan)
dual = read(ROOT/'DUAL.json')
engine = power_engine()
engine = power_engine(verified['vendor/fine_moment.py'])
result = certify(local, inventory, stock, dual, engine)
parent = {int(k): v for k, v in read(ROOT/'inputs/pr2269-profile.json').items()}
_, parent_hi = engine.moment(73, 66304, list(parent.items()), Q(dual['threshold']))
Expand Down
Loading