Analyze usercmd caller keys hash and command bundles
Browse files- docs/ASSET_PIPELINE_TODO.md +2 -0
- docs/FINDINGS.md +6 -0
- docs/PROVISIONAL_TODO.md +2 -0
- docs/RESEARCH_LEDGER.md +6 -0
- docs/REVERSE_ENGINEERING_TODO.md +5 -0
- docs/research/MESSAGE_USERCMD.md +2 -0
- docs/research/README.md +2 -0
- docs/research/USERCMD_CALLERS.md +41 -0
- docs/research/usercmd-callers.json +0 -0
- scripts/analyze_usercmd_callers.py +95 -0
- scripts/test_usercmd_callers.py +75 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -240,3 +240,5 @@ Research progress: [scalar message deltas](research/MESSAGE_DELTA.md) adds integ
|
|
| 240 |
Research progress: [keyed message deltas](research/MESSAGE_DELTA_KEY.md) adds integer mask/XOR and finite float compressed contracts (RE-389–391). RE-392 retains caller/index/runtime/higher-level/packet/platform work; broad networking conversion remains open.
|
| 241 |
|
| 242 |
Research progress: [keyed usercmd codecs](research/MESSAGE_USERCMD.md) completes bounded RE-393–395 (time/key dispatch, record fields/narrowing and 204 modeled-tree streams). RE-392/396 retain legal callers, packet baselines/higher-level codecs and actual runtime/platform work; broad networking and rendering milestones remain open.
|
|
|
|
|
|
|
|
|
| 240 |
Research progress: [keyed message deltas](research/MESSAGE_DELTA_KEY.md) adds integer mask/XOR and finite float compressed contracts (RE-389–391). RE-392 retains caller/index/runtime/higher-level/packet/platform work; broad networking conversion remains open.
|
| 241 |
|
| 242 |
Research progress: [keyed usercmd codecs](research/MESSAGE_USERCMD.md) completes bounded RE-393–395 (time/key dispatch, record fields/narrowing and 204 modeled-tree streams). RE-392/396 retain legal callers, packet baselines/higher-level codecs and actual runtime/platform work; broad networking and rendering milestones remain open.
|
| 243 |
+
|
| 244 |
+
Research progress: [usercmd caller/hash/bundle evidence](research/USERCMD_CALLERS.md) completes bounded RE-397–399. RE-396/400 retain state producers, timestamp/VM acceptance, full bundle/netchan/runtime/platform and higher-level codecs; broad game/network/rendering milestones remain open.
|
docs/FINDINGS.md
CHANGED
|
@@ -450,3 +450,9 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 450 |
**F-155 — Usercmd masks and stores:** eight fields in a 24-byte record use widths 16/8; movement sign-extends before XOR. Mask16's extra key bit survives full-word stores, while mask8's extra bit is discarded by byte stores. Unchanged aggregate copies the remaining 20 bytes; no keyed mask32 field appears in these graphs. Semantic names and legal high keys remain unverified. [CMD-002](research/MESSAGE_USERCMD.md).
|
| 451 |
|
| 452 |
**F-156 — Usercmd composition and accounting:** 204 synthetic modeled-tree streams agree with independent request/packing/full-record/cursor/diagnostic/canary oracles in both engines. Unchanged commands add seven to oldsize beyond requested widths. No original process/native callee, runtime traffic or full native training executes. [CMD-003](research/MESSAGE_USERCMD.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 450 |
**F-155 — Usercmd masks and stores:** eight fields in a 24-byte record use widths 16/8; movement sign-extends before XOR. Mask16's extra key bit survives full-word stores, while mask8's extra bit is discarded by byte stores. Unchanged aggregate copies the remaining 20 bytes; no keyed mask32 field appears in these graphs. Semantic names and legal high keys remain unverified. [CMD-002](research/MESSAGE_USERCMD.md).
|
| 451 |
|
| 452 |
**F-156 — Usercmd composition and accounting:** 204 synthetic modeled-tree streams agree with independent request/packing/full-record/cursor/diagnostic/canary oracles in both engines. Unchanged commands add seven to oldsize beyond requested widths. No original process/native callee, runtime traffic or full native training executes. [CMD-003](research/MESSAGE_USERCMD.md).
|
| 453 |
+
|
| 454 |
+
**F-157 — Usercmd hash/key callers:** both hash graphs weight signed bytes by 119+index, then XOR signed shifts by 10/20. Both callers hash a 32-byte prefix in 128-slot, 1024-byte reliable-string rings and XOR two state words; corresponding supplied state gives matching full-word keys. Producer semantics/legal key bits remain open. [CALL-001](research/USERCMD_CALLERS.md).
|
| 455 |
+
|
| 456 |
+
**F-158 — Client usercmd bundles:** native selection caps signed command count at 32, omits commands for count <=0 and gates opcodes 2/3. The 64-record, 24-byte command ring starts from a zero baseline and chains previous commands. Every count 1–32 and ring-wrap fixtures match independent stopped-call formulas. [CALL-002](research/USERCMD_CALLERS.md).
|
| 457 |
+
|
| 458 |
+
**F-159 — Server usercmd count and baselines:** signed counts outside 1–32 stop before hash/codec calls; accepted requests use a zero 24-byte baseline then contiguous previous output records. Synthetic supplied codec effects verify the native chain in both engines; timestamp/VM/purity/actual packet behavior remains open. [CALL-003](research/USERCMD_CALLERS.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -552,3 +552,5 @@ Research progress: [scalar message deltas](research/MESSAGE_DELTA.md) completes
|
|
| 552 |
Research progress: [keyed message deltas](research/MESSAGE_DELTA_KEY.md) completes bounded RE-389–391. RE-392 leaves keyed caller/narrowing/index reachability, higher-level codecs and actual runtime/packet/platform contracts open.
|
| 553 |
|
| 554 |
Research progress: [keyed usercmd codecs](research/MESSAGE_USERCMD.md) completes bounded RE-393–395 (time/key dispatch, record fields/narrowing and 204 modeled-tree streams). RE-392/396 retain legal callers, packet baselines/higher-level codecs and actual runtime/platform work; broad networking and rendering milestones remain open.
|
|
|
|
|
|
|
|
|
| 552 |
Research progress: [keyed message deltas](research/MESSAGE_DELTA_KEY.md) completes bounded RE-389–391. RE-392 leaves keyed caller/narrowing/index reachability, higher-level codecs and actual runtime/packet/platform contracts open.
|
| 553 |
|
| 554 |
Research progress: [keyed usercmd codecs](research/MESSAGE_USERCMD.md) completes bounded RE-393–395 (time/key dispatch, record fields/narrowing and 204 modeled-tree streams). RE-392/396 retain legal callers, packet baselines/higher-level codecs and actual runtime/platform work; broad networking and rendering milestones remain open.
|
| 555 |
+
|
| 556 |
+
Research progress: [usercmd caller/hash/bundle evidence](research/USERCMD_CALLERS.md) completes bounded RE-397–399. RE-396/400 retain state producers, timestamp/VM acceptance, full bundle/netchan/runtime/platform and higher-level codecs; broad game/network/rendering milestones remain open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -259,3 +259,9 @@ Completed bounded RE-389–391 with `analyze_message_delta_key.py`: 22 verified
|
|
| 259 |
Completed bounded RE-393–395 with `analyze_message_usercmd.py`: 18 verified graphs across the Linux ELF64 engines and 204 compressed usercmd streams. CMD-001–003/F-154–156 recover signed timestamp short/full dispatch, timestamp-derived keys, aggregate and eight per-field gates, the observed 24-byte layout, signed movement XOR and byte-versus-word narrowing. Synthetic negative deltas can separate decoded/new timestamps and therefore reader/writer keys; legal caller time/key behavior and field semantic confirmation remain open. Actual mask8/mask16 bytes and native/disassembly/dependency hashes are retained. Byte stores discard the extra key bit while full-word stores retain it. Unchanged commands add seven directly to oldsize beyond requested widths. Compositions stop at child boundaries, omit PUSH/POP/save/restores and explicitly preserve caller registers across disjoint synthetic frames; trees remain MODEL-DERIVED and no original process/native callee executes. Eight independent tests verify timestamp boundaries/wrap, aggregate/per-field requests, complete decoded records, raw/codeword packing/cursors, accounting/diagnostics/canaries/source retention, file/dependency identities, paired outcomes and low-byte XOR support. All 398 tests pass. RE-392 remains open; RE-396 tracks caller keys/timestamps/legal domains, packet bundling/baselines, semantic confirmation, entity/player/snapshot tables/codecs, alias/truncation/EOF/overflow/reset behavior, native training and actual packet/runtime/all-platform/renderer contracts before Rust compatibility decisions.
|
| 260 |
|
| 261 |
Validation: all preceding composition reports regenerated byte-identically; the new usercmd report reproduced twice byte-identically. Storage policy (including normal-Git size/filter setup), documentation links and whitespace checks pass.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
Completed bounded RE-393–395 with `analyze_message_usercmd.py`: 18 verified graphs across the Linux ELF64 engines and 204 compressed usercmd streams. CMD-001–003/F-154–156 recover signed timestamp short/full dispatch, timestamp-derived keys, aggregate and eight per-field gates, the observed 24-byte layout, signed movement XOR and byte-versus-word narrowing. Synthetic negative deltas can separate decoded/new timestamps and therefore reader/writer keys; legal caller time/key behavior and field semantic confirmation remain open. Actual mask8/mask16 bytes and native/disassembly/dependency hashes are retained. Byte stores discard the extra key bit while full-word stores retain it. Unchanged commands add seven directly to oldsize beyond requested widths. Compositions stop at child boundaries, omit PUSH/POP/save/restores and explicitly preserve caller registers across disjoint synthetic frames; trees remain MODEL-DERIVED and no original process/native callee executes. Eight independent tests verify timestamp boundaries/wrap, aggregate/per-field requests, complete decoded records, raw/codeword packing/cursors, accounting/diagnostics/canaries/source retention, file/dependency identities, paired outcomes and low-byte XOR support. All 398 tests pass. RE-392 remains open; RE-396 tracks caller keys/timestamps/legal domains, packet bundling/baselines, semantic confirmation, entity/player/snapshot tables/codecs, alias/truncation/EOF/overflow/reset behavior, native training and actual packet/runtime/all-platform/renderer contracts before Rust compatibility decisions.
|
| 260 |
|
| 261 |
Validation: all preceding composition reports regenerated byte-identically; the new usercmd report reproduced twice byte-identically. Storage policy (including normal-Git size/filter setup), documentation links and whitespace checks pass.
|
| 262 |
+
|
| 263 |
+
## 2026-10-11 — Usercmd hash, caller keys and command bundles
|
| 264 |
+
|
| 265 |
+
Completed bounded RE-397–399 with `analyze_usercmd_callers.py`: five verified graphs across both Linux ELF64 engines, 120 evaluated hash probes, 156 server count/key/chain probes, 128 client loop probes, 100 client count/opcode selection probes and six client key derivation probes. CALL-001–003/F-157–159 recover signed-byte weighted hashing and signed shift mixing, 32-byte hash-prefix requests in 128-slot reliable-string rings, full-word XOR keys, client command-count cap/opcode gates, 64-record command ring and server signed 1–32 gate. Client loops generate 2,112 stopped codec requests; server loops generate 1,308. Zero/previous-command baselines are verified by independent address formulas and supplied server child-output byte patterns. Semantic state names and actual producer/time/key domains remain provisional. Hash instructions evaluate supplied memory; caller hash returns and codec child outputs remain explicitly supplied, and client codecs stop at requests. No packet bytes, original process/native callee, netchan/VM/purity or runtime traffic executes. Nine independent tests verify hash arithmetic, server gates/keys/string rings/baseline bytes, every client count and wrapping, count/opcode selection, paired client/server keys and engine outcomes, and verified identities/boundaries. All 407 tests pass; storage, links and whitespace checks pass. RE-396 remains open; RE-400 tracks checksum-feed/acknowledgement/reliable-string producer semantics/sanitation, command generation/server timestamp acceptance/VM dispatch, complete codec/bundle/header/reliability/netchan compositions, real traffic/all-platform validation, entity/player/snapshot and Rust/Bevy/Solari goals.
|
| 266 |
+
|
| 267 |
+
Validation: all preceding composition reports regenerated byte-identically; the new caller report reproduced twice byte-identically. Storage policy/filter setup, documentation links and whitespace checks pass.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -477,3 +477,8 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 477 |
- [x] RE-394 Recover 24-byte record offsets, aggregate/eight field gates, widths, signed movement and byte/word mask narrowing from both Linux ELF64 engines. [CMD-002](research/MESSAGE_USERCMD.md).
|
| 478 |
- [x] RE-395 Compose 204 modeled-tree keyed usercmd streams; independently verify requests, payload/record/cursor/accounting/diagnostic/canary/paired results and low-byte XOR evaluator support. [CMD-003](research/MESSAGE_USERCMD.md).
|
| 479 |
- [ ] RE-396 Trace usercmd caller keys/timestamps/legal ranges, confirm semantic fields and packet baselines/bundling; recover entity/player/snapshot codecs and tables, alias/EOF/overflow/reset contracts, native seed and real packet/runtime/all-platform behavior before Rust compatibility decisions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 477 |
- [x] RE-394 Recover 24-byte record offsets, aggregate/eight field gates, widths, signed movement and byte/word mask narrowing from both Linux ELF64 engines. [CMD-002](research/MESSAGE_USERCMD.md).
|
| 478 |
- [x] RE-395 Compose 204 modeled-tree keyed usercmd streams; independently verify requests, payload/record/cursor/accounting/diagnostic/canary/paired results and low-byte XOR evaluator support. [CMD-003](research/MESSAGE_USERCMD.md).
|
| 479 |
- [ ] RE-396 Trace usercmd caller keys/timestamps/legal ranges, confirm semantic fields and packet baselines/bundling; recover entity/player/snapshot codecs and tables, alias/EOF/overflow/reset contracts, native seed and real packet/runtime/all-platform behavior before Rust compatibility decisions.
|
| 480 |
+
|
| 481 |
+
- [x] RE-397 Recover bounded Com_HashKey signed-byte arithmetic and caller key/hash-prefix/ring derivation from both Linux ELF64 engines; verify independent hash and matching supplied caller keys. [CALL-001](research/USERCMD_CALLERS.md).
|
| 482 |
+
- [x] RE-398 Recover bounded client packet command-count cap/opcode gates, 64-record usercmd ring and zero/previous baselines across every count 1–32 and ring-wrap cases; stop at codec/helper requests. [CALL-002](research/USERCMD_CALLERS.md).
|
| 483 |
+
- [x] RE-399 Recover bounded server signed 1–32 count gate, key and contiguous zero/previous-command decode chain with explicitly supplied child records. [CALL-003](research/USERCMD_CALLERS.md).
|
| 484 |
+
- [ ] RE-400 Confirm state-field semantic names and checksum-feed/acknowledgement/reliable-string producers/sanitation; trace command generation and server time acceptance/VM dispatch; compose complete bundles/headers/reliability/netchan/fragments with real codec effects, capture runtime traffic and validate other platforms. Continue entity/player/snapshot codecs and Rust/Bevy/Solari goals.
|
docs/research/MESSAGE_USERCMD.md
CHANGED
|
@@ -49,3 +49,5 @@ The shared evaluator adds low-byte XORB support, preserving other register bytes
|
|
| 49 |
No original executable or native callee runs. PUSH/POP and stack save/restores are omitted; synthetic frames and explicit caller-register restoration compose stopped child boundaries. Training remains model-derived, not a complete native seed run. The fixtures use ample initialized buffers and disjoint records. They do not validate truncated/EOF/overflow packets, overlapping pointers, caller key provenance/time invariants, real multiplayer traffic, or other platforms.
|
| 50 |
|
| 51 |
RE-392 remains open for broader keyed callers. RE-396 must trace actual usercmd callers and key provenance, confirm field semantics against QVM/native consumers, recover packet bundling/baselines and entity/player/snapshot field tables, establish legal high-key/timestamp behavior, and compare runtime captures before Rust codec compatibility decisions. Bevy/Solari rendering and macOS/Linux game execution remain separate open milestones.
|
|
|
|
|
|
|
|
|
| 49 |
No original executable or native callee runs. PUSH/POP and stack save/restores are omitted; synthetic frames and explicit caller-register restoration compose stopped child boundaries. Training remains model-derived, not a complete native seed run. The fixtures use ample initialized buffers and disjoint records. They do not validate truncated/EOF/overflow packets, overlapping pointers, caller key provenance/time invariants, real multiplayer traffic, or other platforms.
|
| 50 |
|
| 51 |
RE-392 remains open for broader keyed callers. RE-396 must trace actual usercmd callers and key provenance, confirm field semantics against QVM/native consumers, recover packet bundling/baselines and entity/player/snapshot field tables, establish legal high-key/timestamp behavior, and compare runtime captures before Rust codec compatibility decisions. Bevy/Solari rendering and macOS/Linux game execution remain separate open milestones.
|
| 52 |
+
|
| 53 |
+
Follow-up: [usercmd callers](USERCMD_CALLERS.md) recovers bounded outer key derivation, count/opcode gates and zero/previous command chains. Producer/time legality, complete packet composition and runtime validation remain open.
|
docs/research/README.md
CHANGED
|
@@ -153,3 +153,5 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 153 |
[Keyed delta masks, XOR and compressed compositions](MESSAGE_DELTA_KEY.md) adds RE-389–391: actual integer table/bounds/adjacent reads, finite float XOR and modeled-tree payload/cursor checks. Reproduce with `python3 scripts/analyze_message_delta_key.py`; check with `python3 scripts/test_message_delta_key.py`. Caller/narrowing/index/higher-level and actual packet/runtime/platform contracts remain open.
|
| 154 |
|
| 155 |
[Keyed user-command codecs](MESSAGE_USERCMD.md) adds RE-393–395. Reproduce with `python3 scripts/analyze_message_usercmd.py`; check with `python3 scripts/test_message_usercmd.py`. Caller/time/key provenance, packet/entity/player/snapshot and runtime/platform validation remain open.
|
|
|
|
|
|
|
|
|
| 153 |
[Keyed delta masks, XOR and compressed compositions](MESSAGE_DELTA_KEY.md) adds RE-389–391: actual integer table/bounds/adjacent reads, finite float XOR and modeled-tree payload/cursor checks. Reproduce with `python3 scripts/analyze_message_delta_key.py`; check with `python3 scripts/test_message_delta_key.py`. Caller/narrowing/index/higher-level and actual packet/runtime/platform contracts remain open.
|
| 154 |
|
| 155 |
[Keyed user-command codecs](MESSAGE_USERCMD.md) adds RE-393–395. Reproduce with `python3 scripts/analyze_message_usercmd.py`; check with `python3 scripts/test_message_usercmd.py`. Caller/time/key provenance, packet/entity/player/snapshot and runtime/platform validation remain open.
|
| 156 |
+
|
| 157 |
+
[Usercmd caller keys and bundles](USERCMD_CALLERS.md) adds RE-397–399. Reproduce with `python3 scripts/analyze_usercmd_callers.py`; check with `python3 scripts/test_usercmd_callers.py`. Hash instructions are evaluated; caller hash returns and server codec effects are supplied. Full packet/runtime conformance remains open.
|
docs/research/USERCMD_CALLERS.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Usercmd caller keys, command bundles and hash
|
| 2 |
+
|
| 3 |
+
RE-397–399 / F-157–159. [usercmd-callers.json](usercmd-callers.json) retains five verified native graphs across both Linux ELF64 engines. Reproduce with `python3 scripts/analyze_usercmd_callers.py`; verify with `python3 scripts/test_usercmd_callers.py`.
|
| 4 |
+
|
| 5 |
+
This extends [the keyed usercmd codec](MESSAGE_USERCMD.md). Original executables and native callees never run. The hash instructions are evaluated against supplied string memory. Caller hash returns are supplied separately; writer codec calls stop at argument requests, and server codec output records are explicitly supplied to exercise chaining. This report contains no message bytes, decoded packets or runtime network evidence.
|
| 6 |
+
|
| 7 |
+
## CALL-001 — Hash and caller key derivation (RE-397)
|
| 8 |
+
|
| 9 |
+
Both `Com_HashKey` graphs recover the following sampled contract: return zero for signed max length <=0 or an initial NUL. Accumulate `signed_byte(text[i]) * (119+i)` modulo 32 bits until NUL or the length bound, then return `sum XOR arithmetic_shift(sum,10) XOR arithmetic_shift(sum,20)` as a 32-bit word. High bytes sign-extend; shifts use the signed accumulated word. This is not an unsigned-byte hash. The unrolled graph contains lookahead loads; the tests supply readable padding, so safe minimal allocation/read bounds are not established.
|
| 10 |
+
|
| 11 |
+
Sixty probes per engine cover empty, ASCII, embedded NUL, high bytes 127/128/255 and a 64-byte sequence, with bounds -1, 0, 1, 2, 3, 4, 7, 8, 31 and 32. An independent arithmetic oracle verifies all 120 results, including signed wrap/mix behavior. Function entries: dedicated `0x42b4a8`, client `0x43bd48`.
|
| 12 |
+
|
| 13 |
+
The client requests `Com_HashKey` with length 32 at `0xfb14dc + 1024*(clc[+0x20434] & 127)`. Its final key is the XOR of `clc[+0x20430]`, `clc[+0x424]` and the returned hash. Six instruction slices test ring slots 0/127/wrapped128 and both low/high supplied state words. Inferred interpretations are message acknowledgement, checksum feed and acknowledged server reliable-command text; these semantic identities require producer/consumer confirmation.
|
| 14 |
+
|
| 15 |
+
The server requests the same prefix length at `client + 0x804 + 1024*(client[+0x20808] & 127)`. Its key XORs `client[+0x20810]`, `sv[+0x10]` and the returned hash. These are provisionally the corresponding reliable acknowledgement, message acknowledgement and checksum feed. Paired synthetic state words give matching client/server keys. Neither slice clamps the key to 16 bits; it passes the complete XOR word to the codec. Actual producers, string sanitation and reachable bit distributions remain open. Do not infer legal high-key behavior solely from supplied hash returns.
|
| 16 |
+
|
| 17 |
+
## CALL-002 — Client bundle selection and baselines (RE-398)
|
| 18 |
+
|
| 19 |
+
Client `CL_WritePacket` entry `0x41025a` statically initializes a 0x4000-byte message, selects bitstream mode, writes three state words and loops over pending reliable commands with opcode 4, sequence and string. These preamble calls are retained as graph evidence, not composed here. Packet-dup values below zero or above five branch to Cvar_Set paths; their external effects are not modeled.
|
| 20 |
+
|
| 21 |
+
For supplied packetdup values within 0–5, the command count is current command number minus the prior packet command number selected by `(outgoing_sequence-1-packetdup) & 31`. Prior packet records have observed stride 12; their command-number address is `0xfe2378 + 12*slot`. A signed count above 32 emits a diagnostic and is capped at 32. Counts <=0 skip the command opcode/count/hash/codec portion.
|
| 22 |
+
|
| 23 |
+
When commands exist, opcode 2 is selected only when the no-delta cvar is zero, `cl[+4]` is nonzero, `clc[+0x43a04]` is zero, and `clc[+0x20430] == cl[+0x10]`; all other sampled gates select opcode 3. These are provisionally delta/non-delta move opcodes. The next byte is the capped command count. One hundred selection slices cover zero, negative, 1, 32 and over-cap counts, packet-dup endpoints, sequence wrap and each opcode gate. Helper byte writes and diagnostic calls are stopped and recorded, not executed.
|
| 24 |
+
|
| 25 |
+
The observed usercmd ring is 64 records of stride 24, starting at `0xfe1d74`. For count N, the writer selects records `(current_number+1-N+i) & 63`, i=0..N-1. The first baseline is a zeroed 24-byte stack record; subsequent calls use the immediately preceding selected record. Every call uses the same outer key. The timestamp XOR remains inside each codec invocation, as described in CMD-001.
|
| 26 |
+
|
| 27 |
+
128 loop slices cover every count 1–32 and current numbers 0/63/64/0xffffffff, including ring wrapping and all unrolled remainder paths. Their 2,112 stopped codec requests match independent ring/baseline formulas. The supplied zero baseline is inspected, but these loop slices do not execute the complete packet initializer, command generation or netchan transmit.
|
| 28 |
+
|
| 29 |
+
## CALL-003 — Server count guard and decode chain (RE-399)
|
| 30 |
+
|
| 31 |
+
Server `SV_UserMove` entries: dedicated `0x406b94`, client `0x4714e4`. Start immediately after MSG_ReadByte with an explicitly supplied count return. Signed counts <=0 or >32 reach diagnostic boundaries before hash or codec calls; only 1–32 proceed. Thus supplied -1/0/33 are rejected. This does not independently prove safe handling of every truncated compressed input or decoder cursor condition.
|
| 32 |
+
|
| 33 |
+
Accepted counts initialize a 24-byte zero baseline at supplied frame+0x310. Destinations are frame+0x10+24*i. Each call after the first uses the previous destination as baseline, and all share the derived outer key. The native unrolled loop is evaluated across sampled counts 1/2/3/4/5/7/8/16/31/32, two acknowledgement words and three reliable ring indices. Per engine, 78 probes produce 654 stopped codec requests. Supplied child record patterns prove the baseline bytes follow the immediately prior child output rather than an unrelated preinitialized record.
|
| 34 |
+
|
| 35 |
+
The slice stops before frame acknowledgement metadata, purity/connection-state checks, timestamp filtering, client-state mutation and VM dispatch. Their instructions remain in the graph but are not evaluated in these fixtures. In particular, this work does not resolve the earlier synthetic negative-time path's actual legal reachability.
|
| 36 |
+
|
| 37 |
+
## Validation and next tasks
|
| 38 |
+
|
| 39 |
+
Nine tests independently verify signed-byte hash arithmetic, server count guards, hash ring/key formulas, server zero/contiguous byte baselines, all client counts/ring wraps, packet count/opcode gates, paired key derivation/outcomes and source identities. Caller request/return boundaries and supplied server output effects remain explicit. No original process, network send, VM call or actual codec callee executes.
|
| 40 |
+
|
| 41 |
+
RE-396 remains open for full caller and higher-level validation. RE-400 must trace checksum-feed/acknowledgement/reliable-string producers and sanitation, command generation/time monotonicity, actual server timestamp acceptance/VM dispatch, packet headers/reliable commands/netchan framing and full bundle compositions with the existing codec, then verify captured traffic and other platforms. Entity/player/snapshot codecs, Rust compatibility and Bevy/Solari rendering remain open.
|
docs/research/usercmd-callers.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_usercmd_callers.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Usercmd caller/key/hash slices with explicit supplied codec boundaries."""
|
| 3 |
+
import gzip
|
| 4 |
+
import itertools
|
| 5 |
+
import json
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from analyze_bsp_references import global_address,operand,trace_fields
|
| 8 |
+
from analyze_collision_composition import get_word,put_word
|
| 9 |
+
from analyze_engine_control import control_flow
|
| 10 |
+
from analyze_message_widths import run
|
| 11 |
+
from analyze_qvm import write_json
|
| 12 |
+
from analyze_vm_extensions import native_functions,verified
|
| 13 |
+
|
| 14 |
+
FRAME=0x20000
|
| 15 |
+
CLIENT=0x50000
|
| 16 |
+
MSG=0x10000
|
| 17 |
+
STRING=0x80000
|
| 18 |
+
|
| 19 |
+
def hash_probe(g,text,limit):
|
| 20 |
+
m={STRING+i:v for i,v in enumerate(text+b'\0'*8)};ret=[x['address'] for x in g['instructions'] if x['opcode']=='retq'];t=run(g,g['instructions'][0]['address'],ret,m,{'%rdi':STRING,'%rsi':limit&0xffffffff})
|
| 21 |
+
return {'text_hex':text.hex(),'limit_word':limit&0xffffffff,'result_word':t['registers']['rax']&0xffffffff,**trace_fields(t,False)}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def server_probe(g,count,ack,sequence,seed,hashword):
|
| 25 |
+
# Start after MSG_ReadByte: supply only its return, not a decoded packet.
|
| 26 |
+
rows=g['instructions'];ci=next(i for i,x in enumerate(rows) if '<MSG_ReadByte>' in x['operands']);end=next(x['address'] for x in rows if x['opcode']=='movslq' and operand(x)=='0x20810(%r15), %rbx');calls={x['address']:i for i,x in enumerate(rows) if x['opcode']=='callq'};m={};put_word(m,CLIENT+0x20808,sequence);put_word(m,CLIENT+0x20810,ack);seed_load=next(x for x in rows if x['opcode']=='movl' and '<sv+0x10>' in x['operands']);put_word(m,global_address(seed_load),seed);regs={'%rax':count&0xffffffff,'%rsp':FRAME,'%r15':CLIENT,'%r14':MSG};pc=rows[ci+1]['address'];trace=[];requests=[];hashreq=None;baselines=[];stop='complete'
|
| 27 |
+
while True:
|
| 28 |
+
t=run(g,pc,list(calls)+[end],m,regs);m=t['memory'];regs=t['registers'];trace+=t['trace']
|
| 29 |
+
if t['stop']==end:break
|
| 30 |
+
i=calls[t['stop']];target=rows[i]['operands']
|
| 31 |
+
if '<Com_Printf>' in target:stop='count_rejected';break
|
| 32 |
+
if '<Com_HashKey>' in target:hashreq=[regs['rdi'],regs['rsi']];regs['rax']=hashword
|
| 33 |
+
elif '<MSG_ReadDeltaUsercmdKey>' in target:
|
| 34 |
+
baseline=bytes(m[regs['rdx']+j] for j in range(24));baselines.append(baseline.hex());requests.append([regs[k] for k in ['rdi','rsi','rdx','rcx']]);dest=regs['rcx']
|
| 35 |
+
# Deliberately supplied child output lets native caller chain be checked.
|
| 36 |
+
for j in range(24):m[dest+j]=(len(requests)+j)&255
|
| 37 |
+
if len(requests)==1:zero=baseline.hex()
|
| 38 |
+
if len(requests)>32:raise ValueError('server command bound')
|
| 39 |
+
else:raise ValueError('server unexpected helper '+target)
|
| 40 |
+
pc=rows[i+1]['address']
|
| 41 |
+
return {'count_word':count&0xffffffff,'ack_word':ack,'sequence_word':sequence,'seed_word':seed,'supplied_hash_word':hashword,'hash_request':hashreq,'codec_requests':requests,'baseline_hex':baselines,'first_baseline_hex':zero if requests else None,'stop':stop,**trace_fields({'trace':trace},False)}
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def client_probe(g,count,number,key):
|
| 45 |
+
rows=g['instructions'];start=next(x['address'] for x in rows if x['opcode']=='movl' and '<cl+0x5734>' in x['operands'] and x['address']>next(x['address'] for x in rows if '<Com_HashKey>' in x['operands']));end=next(x['address'] for x in rows if x['opcode']=='movq' and operand(x)=='%rbx, %rdx' and rows[rows.index(x)+1]['opcode']=='movl' and '<clc+0x43a38>' in rows[rows.index(x)+1]['operands']);calls={x['address']:i for i,x in enumerate(rows) if x['opcode']=='callq'}
|
| 46 |
+
number_address=global_address(next(x for x in rows if x['address']==start));m={};put_word(m,number_address,number);put_word(m,FRAME+12,key)
|
| 47 |
+
for j in range(24):m[FRAME+0x4040+j]=0
|
| 48 |
+
regs={'%rbp':count,'%rsp':FRAME,'%r13':MSG};pc=start;requests=[];trace=[]
|
| 49 |
+
while True:
|
| 50 |
+
t=run(g,pc,list(calls)+[end],m,regs);m=t['memory'];regs=t['registers'];trace+=t['trace']
|
| 51 |
+
if t['stop']==end:break
|
| 52 |
+
i=calls[t['stop']]
|
| 53 |
+
if '<MSG_WriteDeltaUsercmdKey>' not in rows[i]['operands']:raise ValueError('client unexpected boundary')
|
| 54 |
+
requests.append([regs[k] for k in ['rdi','rsi','rdx','rcx']]);pc=rows[i+1]['address']
|
| 55 |
+
if len(requests)>32:raise ValueError('client command bound')
|
| 56 |
+
return {'count':count,'command_number_word':number,'supplied_key_word':key,'command_number_address':number_address,'codec_requests':requests,'zero_baseline_hex':bytes(m[FRAME+0x4040+j] for j in range(24)).hex(),**trace_fields({'trace':trace},False)}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def client_key_probe(g,ack,sequence,seed,hashword):
|
| 60 |
+
rows=g['instructions'];hc=next(i for i,x in enumerate(rows) if '<Com_HashKey>' in x['operands']);start=next(x['address'] for x in rows if x['opcode']=='movslq' and '<clc+0x20434>' in x['operands']);end=next(x['address'] for x in rows[hc+1:] if x['opcode']=='testl' and operand(x)=='%ebp, %ebp');m={}
|
| 61 |
+
for tag,value in [('<clc+0x20434>',sequence),('<clc+0x20430>',ack),('<clc+0x424>',seed)]:
|
| 62 |
+
x=next(x for x in rows if x['address']>=start and tag in x['operands']);put_word(m,global_address(x),value)
|
| 63 |
+
t=run(g,start,[rows[hc]['address']],m,{'%rsp':FRAME});req=[t['registers'][k] for k in ['rdi','rsi']];regs=t['registers'];regs['rax']=hashword;t2=run(g,rows[hc+1]['address'],[end],t['memory'],regs)
|
| 64 |
+
return {'ack_word':ack,'sequence_word':sequence,'seed_word':seed,'supplied_hash_word':hashword,'hash_request':req,'key_word':get_word(t2['memory'],FRAME+12),**trace_fields({'trace':t['trace']+t2['trace']},False)}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def client_selection(g,dup,outgoing,number,previous,mode):
|
| 68 |
+
rows=g['instructions'];start=next(x['address'] for x in rows if x['opcode']=='movl' and '<clc+0x43a38>' in x['operands']);end=next(x['address'] for x in rows if x['opcode']=='movslq' and '<clc+0x20434>' in x['operands']);empty=[x['address'] for x in rows if x['opcode']=='leaq' and operand(x)=='0x4040(%rsp), %rdx'][-1];calls={x['address']:i for i,x in enumerate(rows) if x['opcode']=='callq'};m={};cvar=0x90000;put_word(m,cvar+48,dup)
|
| 69 |
+
for tag,value in [('<clc+0x43a38>',outgoing),('<cl+0x5734>',number),('<cl+0x4>',mode[1]),('<clc+0x43a04>',mode[2]),('<clc+0x20430>',mode[3]),('<cl+0x10>',mode[4])]:
|
| 70 |
+
x=next(x for x in rows if tag in x['operands']);put_word(m,global_address(x),value)
|
| 71 |
+
for tag,value,ptr in [('<cl_showSend>',0,0x91000),('<cl_nodelta>',mode[0],0x92000)]:
|
| 72 |
+
x=next(x for x in rows if tag in x['operands']);put_word(m,global_address(x),ptr,8);put_word(m,ptr+48,value)
|
| 73 |
+
number_addr=global_address(next(x for x in rows if '<cl+0x5734>' in x['operands']));slot=(outgoing-1-dup)&31;put_word(m,number_addr+4+12*slot,previous);regs={'%rdx':cvar,'%r13':MSG,'%rsp':FRAME};pc=start;trace=[];requests=[];diagnostics=0
|
| 74 |
+
while True:
|
| 75 |
+
t=run(g,pc,list(calls)+[end,empty],m,regs);m=t['memory'];regs=t['registers'];trace+=t['trace']
|
| 76 |
+
if t['stop'] in [end,empty]:break
|
| 77 |
+
i=calls[t['stop']];target=rows[i]['operands']
|
| 78 |
+
if '<MSG_WriteByte>' in target:requests.append([regs['rdi'],regs['rsi']])
|
| 79 |
+
elif '<Com_Printf>' in target:diagnostics+=1
|
| 80 |
+
else:raise ValueError('selection boundary '+target)
|
| 81 |
+
pc=rows[i+1]['address']
|
| 82 |
+
return {'packetdup':dup,'outgoing_sequence_word':outgoing,'command_number_word':number,'previous_command_word':previous,'packet_slot':slot,'mode_words':mode,'byte_requests':requests,'count_register_word':regs['rbp']&0xffffffff,'diagnostic_calls':diagnostics,'stop':'empty' if t['stop']==empty else 'commands',**trace_fields({'trace':trace},False)}
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def main():
|
| 86 |
+
out={'native':{},'limitations':'Verified static graphs and bounded synthetic Linux ELF64 instruction slices only. Original processes/native callees never execute. Com_HashKey instructions evaluated; caller hash returns supplied separately. Usercmd codecs are stopped: server record outputs supplied explicitly and client emits requests only. No message bytes/cursor/EOF/overflow/netchan/purity/VM execution or actual packet conformance. Caller semantic state names provisional; time/key producer and legal domain validation open.'}
|
| 87 |
+
for label in ['linux--Quake3-UrT-Ded.x86_64','linux--Quake3-UrT.x86_64']:
|
| 88 |
+
r=json.loads(Path(f'docs/research/native/{label}.json').read_text());verified((Path('.cache/UrbanTerror43')/r['source']['path']).read_bytes(),r['source']['sha256']);a=r['artifacts']['disassembly.txt'];fs=native_functions(verified(gzip.open(a['path'],'rb').read(),a['uncompressed_sha256']).decode());names=['Com_HashKey','SV_UserMove']+(['CL_WritePacket'] if 'CL_WritePacket' in fs else []);graphs={n:control_flow(fs[n]) for n in names};hashes=[hash_probe(graphs['Com_HashKey'],text,limit) for text,limit in itertools.product([b'',b'a',b'hello',b'a\0ignored',bytes([127,128,255]),bytes(range(1,65))],[-1,0,1,2,3,4,7,8,31,32])];server=[server_probe(graphs['SV_UserMove'],count,ack,sequence,0x12345678,0x87654321) for count,ack,sequence in itertools.product([-1,0,1,2,3,4,5,7,8,16,31,32,33],[0,0xffffffff],[0,127,128])];entry={'source':r['source'],'disassembly_sha256':a['uncompressed_sha256'],'graphs':graphs,'hash_probes':hashes,'server_probes':server}
|
| 89 |
+
if 'CL_WritePacket' in graphs:
|
| 90 |
+
entry['client_probes']=[client_probe(graphs['CL_WritePacket'],count,number,0xa5a5a5a5) for count,number in itertools.product(range(1,33),[0,63,64,0xffffffff])];entry['client_selection_probes']=[client_selection(graphs['CL_WritePacket'],dup,outgoing,64,previous,mode) for dup,outgoing,previous,mode in itertools.product([0,5],[0,32],[64,63,32,31,65],[[0,1,0,7,7],[1,1,0,7,7],[0,0,0,7,7],[0,1,1,7,7],[0,1,0,7,8]])];entry['client_key_probes']=[client_key_probe(graphs['CL_WritePacket'],ack,sequence,0x12345678,0x87654321) for ack,sequence in itertools.product([0,0xffffffff],[0,127,128])]
|
| 91 |
+
out['native'][label]=entry
|
| 92 |
+
write_json(Path('docs/research/usercmd-callers.json'),out);print('Recovered hash and bounded usercmd caller key/baseline chains')
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
if __name__=='__main__':main()
|
scripts/test_usercmd_callers.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Independent hash and stopped caller key/baseline-chain checks."""
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
import unittest
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def signed(v):return v if v<2**31 else v-2**32
|
| 10 |
+
|
| 11 |
+
def hash_oracle(text,limit):
|
| 12 |
+
n=max(0,signed(limit));total=0
|
| 13 |
+
for i,v in enumerate(text[:n]):
|
| 14 |
+
if not v:break
|
| 15 |
+
total=(total+(v if v<128 else v-256)*(119+i))&0xffffffff
|
| 16 |
+
return (total^(signed(total)>>10)^(signed(total)>>20))&0xffffffff
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class UsercmdCallerTests(unittest.TestCase):
|
| 20 |
+
@classmethod
|
| 21 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/usercmd-callers.json').read_text())
|
| 22 |
+
|
| 23 |
+
def test_hash_signed_bytes_lengths_termination_and_shift_mix(self):
|
| 24 |
+
for n in self.r['native'].values():
|
| 25 |
+
self.assertEqual(len(n['hash_probes']),60)
|
| 26 |
+
for p in n['hash_probes']:self.assertEqual(p['result_word'],hash_oracle(bytes.fromhex(p['text_hex']),p['limit_word']))
|
| 27 |
+
|
| 28 |
+
def test_server_count_signed_guard(self):
|
| 29 |
+
for n in self.r['native'].values():
|
| 30 |
+
self.assertEqual(len(n['server_probes']),78)
|
| 31 |
+
for p in n['server_probes']:
|
| 32 |
+
valid=1<=signed(p['count_word'])<=32;self.assertEqual(p['stop'],'complete' if valid else 'count_rejected');self.assertEqual(len(p['codec_requests']),p['count_word'] if valid else 0);self.assertEqual(p['hash_request'] is not None,valid)
|
| 33 |
+
|
| 34 |
+
def test_server_key_and_reliable_command_ring(self):
|
| 35 |
+
for n in self.r['native'].values():
|
| 36 |
+
for p in n['server_probes']:
|
| 37 |
+
if p['stop']!='complete':continue
|
| 38 |
+
self.assertEqual(p['hash_request'],[0x50000+0x804+1024*(p['sequence_word']&127),32]);key=p['ack_word']^p['seed_word']^p['supplied_hash_word']
|
| 39 |
+
for msg,k,base,dest in p['codec_requests']:self.assertEqual(msg,0x10000);self.assertEqual(k,key)
|
| 40 |
+
|
| 41 |
+
def test_server_zero_and_contiguous_previous_command_baselines(self):
|
| 42 |
+
for n in self.r['native'].values():
|
| 43 |
+
for p in n['server_probes']:
|
| 44 |
+
for i,(msg,key,base,dest) in enumerate(p['codec_requests']):
|
| 45 |
+
self.assertEqual(dest,0x20000+16+24*i);self.assertEqual(base,0x20000+0x310 if i==0 else dest-24);self.assertEqual(p['baseline_hex'][i],bytes(24).hex() if i==0 else bytes((i+j)&255 for j in range(24)).hex())
|
| 46 |
+
|
| 47 |
+
def test_client_all_counts_ring_wrap_and_baseline_chain(self):
|
| 48 |
+
n=self.r['native']['linux--Quake3-UrT.x86_64'];self.assertEqual(len(n['client_probes']),128)
|
| 49 |
+
for p in n['client_probes']:
|
| 50 |
+
self.assertEqual(len(p['codec_requests']),p['count']);self.assertEqual(p['zero_baseline_hex'],bytes(24).hex())
|
| 51 |
+
for i,(msg,key,base,dest) in enumerate(p['codec_requests']):
|
| 52 |
+
ring=0xfe1d74+24*((p['command_number_word']+1-p['count']+i)&63);self.assertEqual(dest,ring);self.assertEqual(base,0x20000+0x4040 if i==0 else p['codec_requests'][i-1][3]);self.assertEqual(key,p['supplied_key_word']);self.assertEqual(msg,0x10000)
|
| 53 |
+
|
| 54 |
+
def test_client_packetdup_count_clamp_and_mode(self):
|
| 55 |
+
rows=self.r['native']['linux--Quake3-UrT.x86_64']['client_selection_probes'];self.assertEqual(len(rows),100)
|
| 56 |
+
for p in rows:
|
| 57 |
+
count=signed((p['command_number_word']-p['previous_command_word'])&0xffffffff);self.assertEqual(p['packet_slot'],(p['outgoing_sequence_word']-1-p['packetdup'])&31);self.assertEqual(p['count_register_word'],min(count,32)&0xffffffff);self.assertEqual(p['diagnostic_calls'],int(count>32));self.assertEqual(p['stop'],'commands' if count>0 else 'empty');mode=p['mode_words'];opcode=2 if mode[0]==0 and mode[1]!=0 and mode[2]==0 and mode[3]==mode[4] else 3;self.assertEqual(p['byte_requests'],[[0x10000,opcode],[0x10000,min(count,32)]] if count>0 else [])
|
| 58 |
+
|
| 59 |
+
def test_client_key_hash_prefix_ring_and_server_match(self):
|
| 60 |
+
n=self.r['native']['linux--Quake3-UrT.x86_64'];self.assertEqual(len(n['client_key_probes']),6)
|
| 61 |
+
for p in n['client_key_probes']:
|
| 62 |
+
self.assertEqual(p['hash_request'],[0xfb14dc+1024*(p['sequence_word']&127),32]);self.assertEqual(p['key_word'],p['ack_word']^p['seed_word']^p['supplied_hash_word']);server=next(q for q in n['server_probes'] if q['count_word']==1 and q['ack_word']==p['ack_word'] and q['sequence_word']==p['sequence_word']);self.assertEqual(p['key_word'],server['codec_requests'][0][1])
|
| 63 |
+
|
| 64 |
+
def test_paired_server_and_hash_outcomes(self):
|
| 65 |
+
a,b=self.r['native'].values()
|
| 66 |
+
def clean(rows):return [{k:v for k,v in p.items() if k!='trace_sha256'} for p in rows]
|
| 67 |
+
self.assertEqual(clean(a['server_probes']),clean(b['server_probes']));self.assertEqual(clean(a['hash_probes']),clean(b['hash_probes']))
|
| 68 |
+
|
| 69 |
+
def test_verified_sources_and_explicit_boundaries(self):
|
| 70 |
+
for n in self.r['native'].values():
|
| 71 |
+
data=(Path('.cache/UrbanTerror43')/n['source']['path']).read_bytes();self.assertEqual(hashlib.sha256(data).hexdigest(),n['source']['sha256']);self.assertEqual(n['source'],json.loads(Path('docs/research/native').joinpath(next(label for label,v in self.r['native'].items() if v is n)+'.json').read_text())['source'])
|
| 72 |
+
calls=[x['operands'] for x in n['graphs']['SV_UserMove']['instructions'] if x['opcode']=='callq'];self.assertEqual(sum('<MSG_ReadDeltaUsercmdKey>' in s for s in calls),8);self.assertIn('supplied explicitly',self.r['limitations'])
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if __name__=='__main__':unittest.main()
|