Metadata-Version: 2.4
Name: attested-relay-timelock
Version: 0.2.0a4
Summary: Native RandomX solver and checkpoint manager for attested relay archives
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: RANDOMX-LICENSE
Provides-Extra: archive
Requires-Dist: attested-relay<0.3,>=0.2.0a1; extra == "archive"
Provides-Extra: follow
Requires-Dist: attested-relay<0.3,>=0.2.0a1; extra == "follow"
Dynamic: license-file

# attested-relay-timelock

This package bundles the native Rust RandomX v2.0.1 generator, solver, checkpoint
journal, calibration, and archive decryption commands in a platform wheel.
It has no Python substitute for RandomX. Build the wheel from this complete
repository with `pip wheel --no-deps ./python/attested-relay-timelock` (Rust,
CMake, and a C++ compiler are required). Source-only PyPI installation is not
supported; publish the platform wheels after native validation on each platform.

```
attested-relay-timelock calibrate --mode full --samples 10000
attested-relay-timelock solve --manifest puzzle.json \
  --service-public-key ATTESTATION_VERIFIED_ED25519_HEX \
  --checkpoint epoch.jsonl --key-out epoch.key
attested-relay-timelock decrypt-record --manifest puzzle.json \
  --service-public-key ATTESTATION_VERIFIED_ED25519_HEX \
  --epoch-key epoch.key --record ciphertext.json --plaintext-out record.bin
```

Re-run the identical solve command after a restart to resume. The append-only
journal preserves completed entries after interrupted writes. Checkpoint digests
detect accidental corruption; checkpoints are local progress hints, and a malicious
writer can waste computation but cannot produce a returned key without passing
the segment AEAD and published epoch-key commitment. Protect the journal directory.

The public key is a required independent trust pin, obtained from verified
attestation or a previously verified archived identity. A manifest's self-reported
signer does not establish trust.

The high-level `Puzzle` API uses an authenticated archive **bundle** URL:

```python
from attested_relay_timelock import Puzzle

puzzle = Puzzle.from_url(
    "https://relay.girl.surgery/v1/artifacts/SHA256.bundle.json",
    expected_pcr0=INDEPENDENTLY_VERIFIED_PCR0_HEX,
)
epoch_key = puzzle.solve(checkpoint="./solver-state/epoch.jsonl")
plaintext = puzzle.decrypt_record(
    "downloaded.record.json",
    epoch_key=epoch_key,
    plaintext_out="./solver-state/decrypted-record.bin",
)
```

Replace `SHA256` with the bundle's actual 64-character content digest. Install
`attested-relay-timelock[archive]` on Python 3.11 or later for this interface;
the existing `follow` extra also installs the archive verifier. A bare
`.puzzle.json` URL is rejected because it lacks the linked Nitro identity
evidence. The required PCR0 pin must come from an independently trusted build
measurement, not from the downloaded archive or its hosting server. Verification
checks every artifact digest, AWS Nitro signature/certificate chain, PCRs,
attested TLS/service keys, Graviton5 policy, manifest signature, and work
parameters. Historical warming evidence is valid here; it does not establish
present service readiness or when a puzzle was made public.

`puzzle.manifest_id`, `puzzle.service_public_key`, `puzzle.manifest`,
`puzzle.policy`, and `puzzle.attestation` expose authenticated metadata. Dictionary
properties return independent copies. `solve()` writes the verified manifest
next to the checkpoint and returns the recovered key's `Path`; its default name
is `<manifest_id>.key`, or set `key_out=` explicitly. It defaults to genuine
native `full` mode; `mode="light"` computes the same result more slowly.
Solving can take days. Interrupt and resume with the same checkpoint/output paths;
an already completed key output raises `FileExistsError` rather than replacing it.
`decrypt_record()` verifies the manifest signature, epoch/key commitment and
record AEAD authentication natively, and creates a new plaintext output. The
record envelope itself has no service signature. Once an epoch key is public,
anyone holding it can create another valid AEAD envelope; identifying the
original archived record then also requires an independently trusted digest or
publication record. Both operations work offline after
`from_url()` completes. Existing differing manifests, keys and plaintext files
are preserved. Protect solver-state directories from other writers.

The native decryptor returns authenticated bytes without interpreting their
encoding. Current audit plaintext is canonical **CBOR version 3**, including a
`software_version` field; decode it with `cbor2.loads(plaintext.read_bytes())`.
Historical diagnostic archives use **JSON version 2**, decoded with
`json.loads(plaintext.read_bytes())`. Inspect the decoded `version` field and
handle only the format/version your application supports. The encrypted
`.record.json` envelope remains JSON in both cases; its filename does not imply
that the decrypted bytes are JSON. `Puzzle` decrypts both formats through the
same native authentication path.

Only explicit `insecure_local=True` permits a loopback HTTP URL (for example,
the operator's SSH archive tunnel). It never disables Nitro/PCR/hardware checks.
Archive fetches share a bounded timeout, reject redirects and enforce size
limits. URLs with credentials, queries or fragments are rejected. There is no
URL-only trust shortcut or development-attestation bypass in this API.

`light` mode uses the genuine RandomX algorithm with a 256 MiB cache and computes
dataset items as needed. `full` uses a shared 2080 MiB dataset for faster execution.
Both produce identical hashes. Production iteration counts must be calibrated in
full mode on the reference CPU, compiled into the enclave image, and measured
under seven-worker load. Short tests never establish a seven-day delay.

Continuous solving uses verified historical bundles and the paginated all-artifact
index, restarting discovery from its first page each poll so newly inserted hashes
are not missed:

```
attested-relay-timelock follow https://relay.example --expected-pcr0 PCR0_HEX \
  --state-dir ./solver-state --max-workers 7
```

Install the `follow` extra (and the matching `attested-relay` package). Each bundle
must pass archived Nitro identity verification before its independently authenticated
service key is handed to the native solver. Seven full-mode solvers require roughly
16 GiB for datasets/caches plus process overhead. Existing verified keys are reused;
failed solvers preserve checkpoints and are retried on later discovery scans. Keys
are stored locally; this command does not publish them to an external service.
