Independent Pi/OpenRouter review: inception/mercury-2.5
Source: a10323dede4413fbf295916b8ad12e3dbad7514e. Status: completed.
A. Can an in-scope adversary recover or infer request/response contents before the intended delay?
SUPPORT CONDITION CONDITIONALLY
Reasoning: The implementation enforces encryption before release to the untrusted host.
- Enclave Isolation: Request and response bodies are captured inside the enclave (
v2_proxy.rsline 155) and encrypted withencrypt_record(timelock.rsline 92) using anepoch_keyderived locally. - Encryption Layer: The record is encrypted via
XChaCha20Poly1305with an HKDF-derived key bound to the puzzle ID. The ciphertext is transmitted via vsock to the host only after this encryption completes (v2_proxy.rsline 105–107). - Host View: The host (
tlproxy-host) only sees encryptedRecordartifacts and the signed puzzle manifest (crates/host/src/artifacts.rs). It lacks theepoch_keyrequired to decrypt. - Assumptions: This holds provided the enclave memory is protected from host introspection (Nitro guarantee) and no side-channel (e.g., timing/power analysis) leaks the
epoch_keybefore the puzzle is solved.
B. Can an adversary obtain epoch keys, private seeds/intermediates or equivalent decryption capability early, or make the service use an already substantially solved puzzle?
SUPPORT CONDITION CONDITIONALLY
Reasoning: The code enforces a strict serial dependency on solving, preventing parallel speedup of the key recovery path.
- Wrapping Chain: The manifest contains 7
wrapped_keys. Eachwrapped_keys[i]holds a key (seeds[i+1]) encrypted under the hash output of segmenti. The finalwrapped_keys[6]holds theepoch_keyencrypted under the hash output of segment 6 (timelock.rslines 365–387). - Solving Dependency: The
solvefunction incrates/timelock/src/lib.rsiterates segments sequentially (lines 476–492). To access the seed for segmenti+1, it must first compute the output of segmenti(the hash chain foriterationssteps) and use it to decryptwrapped_keys[i]. This prevents parallel solving across segments after publication. - Generation vs. Solving: While
generateuses parallel threads for segments (lines 327–350), the resulting puzzle is useless without solving them serially. - Malicious Parent Scheduling: The
v2_epoch.rsloop refuses to activate a new epoch until the previous epoch puzzle is successfully published to the host (activatefunction lines 76–101). If the parent blocks publication ACK, the service halts production (DoS) rather than falling back to a pre-solved puzzle. - Epoch Key Release: The
epoch_keyis held in memory (Zeroizing) until the epoch expires. There is no API for the host to extract keys.
Potential Risks & Unresolved Questions
- Availability: If the host refuses to ACK the publication (lines 107–110
v2_epoch.rs), the enclave stops generating new puzzles (runfunction returns). This is a Denial of Service vector, not a confidentiality break, but affects the service guarantee. - RandomX Primitive: This analysis assumes the RandomX implementation (
crates/timelock/src/randomx.rs) contains no shortcuts. The build process (line 18build/Dockerfile.graviton5) links a vendored library. - Memory Safety: The FFI interface (
crates/timelock/src/randomx.rs) usesunsafepointers for the C-based RandomX library. A memory safety bug in the binding or the C library could leak keys to the kernel or parent before the puzzle is solved.
Recommendation
The code logic correctly implements the intended "serial work on top of parallel generation" requirement. Confidentiality of request/response content is maintained until the puzzle is solved. There are no identified code paths that allow the parent or host to bypass the sequential dependency or inject pre-solved puzzles without violating the attestation binding.