feat(round): sign score reports with the validator's hotkey - #232
Merged
Merged
Conversation
A score report is the payout input: the server averages the validators' verdicts and the composed weights follow that average. The backend now authenticates those reports, so this is the other half — the validator proves the report came from its hotkey. The signature covers the CONTENT, not just the sender. Signing only the hotkey and round would let anyone who observed one report replay its signature over different scores. The rows are sorted into a canonical form, so the wire order cannot change what was signed. `results_message` / `weights_message` are duplicated from the backend deliberately: the two repos cannot import each other on the payout path, so the agreement is pinned as a byte literal in the tests on BOTH sides. If this rendering drifts here without drifting there, every honest report starts being rejected as a forgery — a test failing is how that should be found. The entrypoint loads a bittensor wallet by name, or a hex seed from the environment. The seed goes straight into the keypair and is never returned, printed, or included in an error message: a validator seed in a log is a stolen validator. Signing as one hotkey while claiming another is refused at startup rather than at the compose block, and an unconfigured signer warns loudly that an enforcing backend will refuse its reports. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Member
Author
Self-review before merge (owner-directed; posted for post-merge audit)All checks pass: Python 3.11, 3.12, publisher suite, integration lane, SEV-SNP contract, release, PEM-key gate. What I verified beyond the tests:
Process note: I merged #226/#229/#230 this morning without reading their checks and left main red all day. I read the checks on this one. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pairs with cathedral-cybergym-backend (validator auth). Together they close the hole where
post_resultsaccepted any non-empty hotkey string — and that report is the payout.What the signature covers
The content, not just the sender. Signing only the hotkey and round would let anyone who observed one report replay its signature over different scores. Rows are canonicalised (sorted, normalised decimals), so wire order cannot change what was signed, and the round is bound so last round's signature cannot be replayed into this one.
The duplication is deliberate
results_message/weights_messageexist in both repos because they cannot import each other on the payout path. The agreement is pinned as a byte literal in tests on both sides: if the rendering drifts here without drifting there, every honest report is rejected as a forgery — and a failing test is how that should surface, not a silent loss of every score in a round.The seed
The entrypoint loads a bittensor wallet by name, or a hex seed from the environment. It goes straight into the keypair and is never returned, printed, or put in an error message — a validator seed in a log is a stolen validator. Signing as one hotkey while claiming another is refused at startup, not at the compose block. An unconfigured signer warns that an enforcing backend will refuse its reports.
Verification
109 v2 round tests pass;
ruff checkandruff format --checkclean overcathedral_thin. Unsigned remains a working mode for a local dry run — the client sends nosignaturefield rather than fabricating one.