Mirrors Pulsar / Corona / Magnetar Tier-A shape, scoped honestly: oracle is operational infrastructure, not a primitive submission, so the cover sheet is OVERVIEW.md. Documents added: OVERVIEW.md — cover sheet + two-surface decomposition SPEC.md — state machine, wire format, ZAP plane PROOF-CLAIMS.md — honest narrow claim + evidence TRUSTED-COMPUTING-BASE.md — trust footprint CRYPTOGRAPHER-SIGN-OFF.md — independent review, APPROVED WITH GATES DEPLOYMENT-RUNBOOK.md — operator-facing guidance LEGACY-CLASSICAL.md — opt-in classical disclosure + migration CHANGELOG.md — substantive changes to spec + TCB Distinct domain-separation context "luxfi.oracle.v1" ensures cross-protocol replay between oracle Observations and relay Receipts (which use "luxfi.relay.v1") is structurally prevented.
3.4 KiB
Cryptographer sign-off — luxfi/oracle (Tier-A flip)
Independent review of the oracle's PQ-default flip and ZAP-native transport at the current revision on
mainofgithub.com/luxfi/oracle. Reviewer: cryptographer agent (internal).
Summary
APPROVED WITH GATES for ML-DSA-65-default intra-Lux operator
signing on Observations and OracleRecords, subject to the disclosures
in LEGACY-CLASSICAL.md and the external-source caveats in
TRUSTED-COMPUTING-BASE.md §3.
The oracle correctly decomplects two signing surfaces:
-
Intra-Lux operator surface — gated by
pkg/profile, ML-DSA-65 default, classical refused under strict-PQ. The gate is a single function (~190 LOC). -
External-source surface — Pyth, Chainlink, Bitcoin / Ethereum RPC, market-data APIs. NOT subject to the PQ default; this is correct.
What was reviewed
pkg/profile/profile.go— the gate. Identical shape to relay's gate;ContextTag = "luxfi.oracle.v1".vm/vm.go—RegisterOperatorKey,VerifyObservationSignature,VerifyRecordSignature. Each verifier callsprofile.Verifyexactly once.pkg/zaptransport/zaptransport.go— ZAP wrapper, opaque JSON only. Two message types:MsgOracleObservation(0x59) andMsgOracleRecord(0x5A).cmd/oracled/main.go— wires ZAP listener.- Tests:
pkg/profile/profile_test.go(5 tests pass)vm/observation_pq_test.go(5 tests pass — Observations + Records, happy / strict-refuse / legacy-accept / unregistered)vm/observation_fuzz_test.go(2 fuzz targets, ~50k execs no panics)pkg/zaptransport/zaptransport_test.go(3 e2e tests pass)
Verified green
GOWORK=off go build ./...clean.GOWORK=off go vet ./...clean.GOWORK=off go test -count=1 -race ./...→ all packages pass.- PQ default refuses Ed25519 Observations/Records.
- Legacy toggle accepts Ed25519 with the correct ContextTag.
- Domain separation:
ContextTag = "luxfi.oracle.v1"is distinct from the relay'sluxfi.relay.v1, so cross-protocol replay is structurally prevented. - Unregistered Operator/Executor: refused (no silent-accept).
- JSON fuzz: ≥50k execs each, no panics.
- ZAP e2e: Observation + Record broadcast round-tripped between two ZAP nodes.
Gates (open, deferred)
| ID | Gate | Status |
|---|---|---|
| GATE-1 | Lean / EasyCrypt refinement of the Permit → Verify chain. |
not blocking |
| GATE-2 | Property-based exhaustive enum check (refuse all non-MLDSA65 under Policy{}). |
nice to have |
| GATE-3 | Aggregation-bound formal proof for canonical output under malicious-minority operators. | future |
| GATE-4 | UMA-derived contracts audit refresh under contracts/prediction/. |
external, AGPL-3.0 inheritance |
What is NOT covered
- ML-DSA-65 itself (FIPS 204 + CIRCL).
- External source honesty (a malicious Pyth aggregator reporting wrong values is not a crypto failure).
- Aggregation correctness (median / TWAP are unit-tested separately).
- AGPL-3.0 Solidity contracts.
Conclusion
Ship the PQ-default flip. The two-surface decomposition is sound, the gate is a single function shared verbatim with relay, and the unregistered-operator soundness bug is closed by design (no analogue of the relay's prior log-and-accept silent-pass ever existed here, but the same explicit-refuse pattern is enforced).