Files
EscapistsReintroduced/tools/ordinary_look_evidence.py

231 lines
15 KiB
Python

"""Independent, read-only verification of the bounded ordinary relative-look proof.
Raw native records prove pose changes; helper timestamps only bind requested input
ordering. Display/session/process ownership and complete keyboard delivery remain
separate runner checks. This module never sends input or opens a native process.
"""
import math
import re
NUMBER = r'-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?'
LOOK = 'ERR LOOK OBSERVE: '
INPUT = 'ERR INPUT OBSERVE: '
SCOPE = 'two fixed relative mouse requests with native camera yaw response and return; stationary body; no visual, aiming, multiplayer or general input qualification'
CANCEL_REASONS = {'menu-opened', 'original-binding-changed', 'sample-or-clock-bound',
'native-camera-or-player-context-lost', 'invalid-native-pose', 'explicit-scope-lost'}
def _require(condition, reason):
if not condition:
raise ValueError(reason)
def _number(value):
_require(type(value) in (int, float) and math.isfinite(value) and value >= 0,
'invalid nonnegative numeric timestamp')
return value
def _index(value):
_require(type(value) is int and 1 <= value <= 450, 'invalid sample reference')
return value
def _vector(value):
if value.startswith('<') and value.endswith('>'):
value = value[1:-1]
_require(re.fullmatch(NUMBER + r'(?:\s*,\s*|\s+)' + NUMBER + r'(?:\s*,\s*|\s+)' + NUMBER, value.strip()), 'malformed native vector')
result = tuple(float(v) for v in re.findall(NUMBER, value))
_require(all(math.isfinite(v) and abs(v) <= 10000000 for v in result), 'nonfinite or unbounded native vector')
return result
def _norm(v):
return math.sqrt(sum(x*x for x in v))
def _distance(a, b):
return _norm(tuple(x-y for x, y in zip(a, b)))
def _yaw(v):
_require(.95 <= _norm(v) <= 1.05 and math.hypot(v[0], v[2]) > .1,
'native camera direction is not unit or has no usable horizontal direction')
return math.degrees(math.atan2(v[0], v[2]))
def _delta(a, b):
return (a-b+180) % 360-180
def _native(content, nonce):
_require(type(content) is str and len(content) <= 32*1024*1024, 'console content exceeds bound or is not text')
_require(type(nonce) is str and re.fullmatch(r'[A-Za-z0-9]{1,32}', nonce), 'invalid expected nonce')
look_header = re.compile(r'run=([A-Za-z0-9]{1,32}) sample=(\d+) real=(\d+) (.+)')
input_header = re.compile(r'run=([A-Za-z0-9]{1,32}) sample=(\d+) real=(\d+) world=('+NUMBER+r') (.+)')
pose_pattern = re.compile(r'SAMPLE direction=(.+?) camera=(.+?) body=(.+?) bodyForward=(.+?) turn=(.+)')
input_pattern = re.compile(r'SAMPLE origin=(.+?) forward=('+NUMBER+r') input=(.+?) velocity=(.+?) inventory=(0|1|true|false)')
poses, samples = {}, {}
basis = None; cancelled = None; ready = None; queued = None
last_look = (-1, -1); last_input = (-1, -1, -1)
look_count = input_count = 0
input_events = set(); input_terminal = False
for ordinal, line in enumerate(content.splitlines()):
if LOOK.rstrip() in line:
_require(LOOK in line, 'malformed look prefix')
look_count += 1
_require(look_count <= 452 and line.count(LOOK) == 1, 'look record count or prefix invalid')
match = look_header.fullmatch(line.split(LOOK, 1)[1].strip())
_require(match is not None, 'malformed look record')
actual, sample, real, event = match.groups(); sample, real = int(sample), int(real)
_require(actual == nonce, 'foreign look nonce')
_require(1 <= sample <= 450 and real <= 2147483647, 'look clock/sample outside bound')
_require(sample >= last_look[0] and real >= last_look[1], 'look records reversed')
_require(cancelled is None, 'look records after cancellation')
last_look = sample, real
if event == 'BASIS native-player-camera-world-transform':
_require(basis is None and not poses and sample == 1, 'duplicate or late native camera acknowledgement')
basis = (sample, real, ordinal)
elif event.startswith('SAMPLE '):
_require(basis is not None, 'missing native camera acknowledgement')
match = pose_pattern.fullmatch(event)
_require(match is not None, 'malformed native look sample')
_require(sample == len(poses)+1, 'look samples missing or duplicated')
values = [_vector(v) for v in match.groups()]
direction, camera, body, facing, turn = values
_yaw(direction)
_require(.95 <= _norm(facing) <= 1.05 and math.hypot(facing[0], facing[2]) > .1 and turn[2] == 0, 'invalid body forward or native turn vector')
poses[sample] = dict(sample=sample, real_ms=real, ordinal=ordinal,
direction=direction, camera=camera, body=body, body_forward=facing, turn=turn)
if sample == 1:
_require(real == basis[1], 'native acknowledgement does not bind first camera sample')
elif event.startswith('CANCELLED '):
_require(event[10:] in CANCEL_REASONS, 'unknown look cancellation')
cancelled = dict(sample=sample, real_ms=real, reason=event[10:], ordinal=ordinal)
else:
raise ValueError('unknown look event')
if INPUT.rstrip() in line:
_require(INPUT in line, 'malformed input prefix')
input_count += 1
_require(input_count <= 460 and line.count(INPUT) == 1, 'input record count or prefix invalid')
match = input_header.fullmatch(line.split(INPUT, 1)[1].strip())
_require(match is not None, 'malformed input record')
actual, sample, real, world, event = match.groups()
_require(not input_terminal, 'input records after terminal event')
if not event.startswith('SAMPLE '):
_require(event not in input_events, 'duplicate input event')
input_events.add(event)
sample, real, world = int(sample), int(real), float(world)
_require(actual == nonce, 'foreign input nonce')
_require(0 <= sample <= 450 and real <= 2147483647 and math.isfinite(world) and world >= 0,
'input clock/sample outside bound')
_require(sample >= last_input[0] and real >= last_input[1] and world >= last_input[2], 'input records reversed')
last_input = sample, real, world
if event == 'QUEUED':
_require(queued is None and not samples and sample == 0, 'duplicate or late input queued event')
queued = (sample, real, world)
elif event == 'READY':
# Record() reads the process clock again after the SAMPLE/LOOK
# writes. Bind READY to the latest emitted sample, not to an
# unrealistically identical millisecond. Later sample ordering
# still rejects a READY timestamp beyond the next sample.
_require(ready is None and sample == len(samples) and sample in samples and
0 <= real-samples[sample]['real_ms'] <= 500 and
world == samples[sample]['world_ms'], 'duplicate or unbound input READY')
ready = dict(sample=sample, real_ms=real, ordinal=ordinal)
elif event.startswith('SAMPLE '):
_require(queued is not None and sample == len(samples)+1, 'input samples missing, duplicated or unqueued')
match = input_pattern.fullmatch(event)
_require(match is not None, 'malformed native input sample')
origin, forward, movement, velocity, inventory = match.groups()
forward = float(forward)
_require(math.isfinite(forward), 'nonfinite input forward')
samples[sample] = dict(sample=sample, real_ms=real, world_ms=world, ordinal=ordinal,
origin=_vector(origin), forward=forward, input=_vector(movement),
velocity=_vector(velocity), inventory=inventory in ('1', 'true'))
elif event in ('INVENTORY_OPEN', 'INVENTORY_CLOSED', 'CAPTURE_REQUEST baseline',
'CAPTURE_REQUEST open', 'CAPTURE_REQUEST closed', 'FINISHED observation-bound'):
input_terminal = event == 'FINISHED observation-bound'
# Complete menu sequencing is independently checked by the runner.
elif event.startswith('CANCELLED '):
_require(bool(event[10:].strip()), 'empty input cancellation')
input_terminal = True
# A later shutdown is outside the look proof, but cannot erase an earlier loss.
for pose in poses.values():
_require(pose['real_ms'] < real, 'input cancellation overlaps native look samples')
else:
raise ValueError('unknown input event')
_require(basis is not None and poses and ready is not None and queued is not None,
'missing native camera acknowledgement, samples or input READY')
_require(ready['real_ms']-queued[1] >= 2000, 'input READY has no stationary baseline duration')
for index, pose in poses.items():
_require(index in samples and samples[index]['real_ms'] == pose['real_ms'], 'native pose/input sample binding mismatch')
_require(0 <= pose['real_ms']-queued[1] < 45000, 'native pose outside original observation lifetime')
return poses, samples, ready, cancelled
def validate_look_evidence(content, nonce, look_proof, keyboard_events=None):
"""Fail closed; recompute native geometry independently of helper claims."""
result = {'verified': False, 'errors': [], 'scope': SCOPE}
try:
_require(type(look_proof) is dict and set(look_proof) == {
'requested', 'completed', 'started_monotonic', 'finished_monotonic',
'baseline_samples', 'response_sample', 'return_sample', 'motions'}, 'unknown or missing look proof fields')
_require(look_proof['requested'] is True and look_proof['completed'] is True, 'look proof not explicitly requested and completed')
start = _number(look_proof['started_monotonic']); finish = _number(look_proof['finished_monotonic'])
_require(0 < finish-start <= 4, 'helper look interval outside four-second bound')
baseline = look_proof['baseline_samples']
_require(type(baseline) is list and len(baseline) == 2, 'exactly two baseline sample references required')
first, base = [_index(i) for i in baseline]
response = _index(look_proof['response_sample']); returned = _index(look_proof['return_sample'])
_require(base == first+1 and base < response < returned, 'baseline/response/return sample ordering invalid')
poses, samples, ready, cancelled = _native(content, nonce)
_require(first >= ready['sample'] and all(i in poses for i in (first, base, response, returned)), 'native ready baseline/response/return missing')
_require(cancelled is None or cancelled['sample'] > returned, 'native camera context cancelled before return')
motions = look_proof['motions']
_require(type(motions) is list and len(motions) == 2, 'exactly two relative motions required')
times = []
for event, dx, after in zip(motions, (24, -24), (base, response)):
_require(type(event) is dict and set(event) == {'dx', 'dy', 'monotonic', 'after_sample', 'after_real_ms'}, 'unknown or missing motion fields')
_require(type(event['dx']) is int and event['dx'] == dx and type(event['dy']) is int and event['dy'] == 0, 'motion differs from fixed relative request')
_require(type(event['after_sample']) is int and event['after_sample'] == after and
type(event['after_real_ms']) is int and event['after_real_ms'] == poses[after]['real_ms'], 'motion native reference mismatch')
times.append(_number(event['monotonic']))
_require(start <= times[0] < times[1] <= finish, 'motion timestamps reversed or outside proof')
_require(0 < poses[returned]['real_ms']-poses[first]['real_ms'] <= 4000, 'native look interval outside four-second bound')
_require(poses[response]['real_ms'] > poses[base]['real_ms'] and poses[returned]['real_ms'] > poses[response]['real_ms'], 'native response/return clocks did not advance')
for index in range(ready['sample'], returned+1):
_require(index in poses and index in samples, 'missing native observation during look proof')
pose, sample = poses[index], samples[index]
_require(index == ready['sample'] or 0 < pose['real_ms']-poses[index-1]['real_ms'] <= 500, 'native look sampling gap or duplicate clock')
_require(not sample['inventory'] and abs(sample['forward']) <= .01 and _norm(sample['input']) <= .01 and _norm(sample['velocity']) <= .05,
'body input, velocity or inventory changed during look proof')
_require(_distance(sample['origin'], samples[ready['sample']]['origin']) <= .05 and
_distance(pose['body'], samples[ready['sample']]['origin']) <= .05 and
_distance(pose['body'], sample['origin']) <= .01, 'body moved or native body/input positions disagree')
base_yaw = _yaw(poses[base]['direction'])
stable = abs(_delta(base_yaw, _yaw(poses[first]['direction'])))
response_yaw = _delta(_yaw(poses[response]['direction']), base_yaw)
return_yaw = _delta(_yaw(poses[returned]['direction']), base_yaw)
_require(stable <= .1, 'camera baseline not stable')
_require(.25 <= abs(response_yaw) <= 30, 'native camera yaw did not show bounded response')
_require(abs(return_yaw) <= .35 and abs(return_yaw) < abs(response_yaw)/2, 'native camera did not return near baseline')
if keyboard_events is not None:
_require(type(keyboard_events) is list and 1 <= len(keyboard_events) <= 8, 'invalid keyboard event list')
previous = -1; first_w = None
for event in keyboard_events:
_require(type(event) is dict and set(event) <= {'key', 'down', 'monotonic', 'finally'} and {'key', 'down', 'monotonic'} <= set(event), 'malformed keyboard event')
_require(event['key'] in ('W', 'Tab') and type(event['down']) is bool and ('finally' not in event or type(event['finally']) is bool), 'unknown keyboard event')
at = _number(event['monotonic']); _require(at >= previous, 'keyboard timestamps reversed'); previous = at
_require(at > finish, 'keyboard request overlaps or precedes look completion')
if first_w is None and event['key'] == 'W' and event['down']:
first_w = at
_require(first_w is not None and keyboard_events[0]['key'] == 'W' and keyboard_events[0]['down'] is True, 'first W press missing or not first keyboard event')
result.update(verified=True, baseline_samples=baseline, response_sample=response, return_sample=returned,
baseline_yaw_delta_degrees=stable, response_yaw_degrees=response_yaw,
return_yaw_degrees=return_yaw, native_duration_ms=poses[returned]['real_ms']-poses[first]['real_ms'],
motion_count=2, keyboard_order_verified=keyboard_events is not None)
except (ValueError, TypeError, KeyError, OverflowError) as error:
result['errors'].append(str(error))
return result