Feature/receive pubkey shares - #28
Merged
Merged
Conversation
tsudmi
approved these changes
Jun 19, 2026
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.
Motivation
A security report (Immunefi #81970) identified three weaknesses in
POST /exit-signature:BLS validation was length-only.
validate_bls_signatureaccepted any 96-byte hex string with no curve membership or subgroup check, making it trivial to submit garbage that passes validation.First-write-wins with no overwrite path. Once a share was stored at a given
(validator_pubkey, share_index), any subsequent submission was silently discarded. An attacker who filled every share slot before legitimate DVT operators submitted would permanently block that validator from exiting — with no recovery path short of a service restart (and the attack repeats immediately after restart).Unhandled exception on reconstruction with no state cleanup. When garbage shares accumulated to the threshold,
reconstruct_shared_bls_signaturewould throw aValueErrorfrompy_ecc(invalid G2 point), propagating as HTTP 500 with the corrupt shares still in memory. There was no way to clear the slot and try again.Changes
Cryptographic validation before storage (
src/validators/schema.py)SignatureShareRequestnow requires callers to submit all operators' public key shares alongside their signature share. Amodel_validatorruns before anything is stored and rejects the request (HTTP 422) unless:share_index;share_index.Because validation happens at the request boundary, only cryptographically valid shares ever reach storage. First-write-wins remains the storage model — but it is now safe, since no garbage can enter.
State cleanup on reconstruction failure (
src/validators/endpoints.py)_reconstruct_exit_signatureand_reconstruct_deposit_signaturewrap the reconstruction and validation step in a try/except that calls.clear()on the shares dict and returns HTTP 400 on any failure. This prevents a corrupt state from becoming permanent even if an invalid share somehow bypassed the earlier check.BLS public key share helpers (
src/validators/key_shares.py,src/validators/exit_signature.py)Added
reconstruct_shared_bls_public_keyand the share-level validatorsvalidate_public_key_shares,validate_exit_signature_share,validate_deposit_signature_shareused by the schema validator above.