Merged
Conversation
l0r1s
reviewed
Nov 25, 2025
Comment on lines
+37
to
+46
| let (sk, pk) = MlKem768::generate(&mut OsRng); | ||
|
|
||
| let sk_bytes = sk.as_bytes(); | ||
| let pk_bytes = pk.as_bytes(); | ||
| let sk_slice: &[u8] = sk_bytes.as_ref(); | ||
| let pk_slice: &[u8] = pk_bytes.as_ref(); | ||
|
|
||
| let current_sk = sk_slice.to_vec(); | ||
| let current_pk = pk_slice.to_vec(); | ||
| let current_fp = blake2_256(pk_slice); |
Collaborator
There was a problem hiding this comment.
Could probably be extracted as a function, this is repeated 3 times
sam0x17
approved these changes
Nov 25, 2025
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.
Summary
This PR introduces MEV‑Shield, an opt‑in encrypted transaction path that makes MEV‑sensitive calls (e.g. staking/unstaking) opaque to mempool observers. Validators rotate per‑block ML‑KEM‑768 keys, announce the next public key on‑chain, and decrypt/execute wrapped calls only in the last portion of each block. Plain extrinsics continue to behave exactly as before.
What’s changing
1. MEV‑Shield authoring hooks & timing
For authority nodes we attach MEV‑Shield to consensus authoring:
role.is_authority():2. Per‑slot ML‑KEM keys and
announce_next_keyWe add per‑slot key management for authorities plus a pallet entrypoint for the “next” key:
ShieldKeysmanages(current, next)ML‑KEM‑768 keypairs;roll_for_next_slotmovesnext → currentand generates a freshnext.spawn_author_tasks:sr25519key; if none is present the node logs a warning and does not announce MEV‑Shield keys.BlockOrigin::Own):announce_at_ms.next_pkfromShieldContext.announce_next_key { public_key: next_pk }extrinsic viasubmit_announce_extrinsic, with simple stale‑nonce retry.The pallet maintains on‑chain key state:
and rolls
NextKey → CurrentKeyinon_initialize.announce_next_keyis an Aura‑validator‑only call that also enforces the Kyber‑768 public key length:3. Encrypted wrappers, revealer, and
execute_revealedWe add a full encrypted wrapper pipeline:
Encrypted submissions on‑chain
commitment = blake2_256(signer || nonce (u32 LE) || SCALE(call)).ciphertext = [u16 kem_len] || kem_ct || nonce24 || aead_ctwhereaead_ctis XChaCha20‑Poly1305 oversigner || nonce || SCALE(call) || sig_kind || signature.Submissionkeyed byid = hash(author, commitment, ciphertext)and emitsEncryptedSubmitted { id, who }.Runtime execution of revealed calls
Submissionwith idid, failing withMissingSubmissionif absent.signer || nonce (u32 LE) || SCALE(call)) and checks:commitmentmatches the stored commitment,signatureverifies against"mev-shield:v1" || genesis_hash || payload,nonceequalsSystem::account_nonce(&signer)(then bumps it).signer.DecryptedExecutedon success orDecryptedRejectedon error;execute_revealeditself is fee‑free (onlysubmit_encryptedpays).Unsigned validation
ValidateUnsignedonly acceptsexecute_revealedwhen:source ∈ { Local, InBlock }, andprovides(id)andpropagate(false).4. Tests
The new tests cover the main flows:
Key announce & roll
authority_can_announce_next_key_and_on_initialize_rolls_it– Aura validator can callannounce_next_key;on_initializepromotesNextKeyintoCurrentKeyand clearsNextKey.announce_next_key_rejects_non_validator_origins– non‑validators and unsigned origins are rejected withBadOrigin.Wrapper lifecycle
submit_encrypted_stores_submission_and_emits_event– stores the expectedSubmissionand emitsEncryptedSubmitted { id, who }.execute_revealed_happy_path_verifies_and_executes_inner_call– reconstructs the payload and commitment, signs the domain‑separated message with sr25519, executesexecute_revealed, consumes the submission, bumps the signer’s nonce, and emitsDecryptedExecuted.Unsigned validation
validate_unsigned_accepts_local_source_for_execute_revealed.validate_unsigned_accepts_inblock_source_for_execute_revealed.