Skip to content

Shielded transactions support in block proposer (with crypto in WASM)#10

Merged
sam0x17 merged 17 commits intopolkadot-stable2506-2-otf-patchesfrom
polkadot-stable2506-2-otf-patches-mev-shield-rework
Mar 2, 2026
Merged

Shielded transactions support in block proposer (with crypto in WASM)#10
sam0x17 merged 17 commits intopolkadot-stable2506-2-otf-patchesfrom
polkadot-stable2506-2-otf-patches-mev-shield-rework

Conversation

@l0r1s
Copy link
Copy Markdown

@l0r1s l0r1s commented Mar 2, 2026

Summary

Companion PR to opentensor/subtensor#2477 - supersedes #6

Adds MEV shield support to Substrate: shielded (encrypted) transaction handling in the block
proposer, along with the shared primitive and client crates (stp-shield, stc-shield) that were
moved here from subtensor to avoid a circular dependency between the two repos.

Users encrypt their extrinsics using ML-KEM-768 + XChaCha20-Poly1305 against the next block
author's public key. At block building time, the proposer passes the decapsulation key to the
runtime, which decrypts each shielded transaction entirely in WASM. Both the wrapper and the inner
extrinsic are then included in the block, keeping transaction contents hidden from the mempool.

Changes

stp-shield (new subtensor primitives crate)

Shared types used by both the runtime and the node side:

  • ShieldedTransaction struct and wire-format parsing
  • ShieldKeystore trait (simplified to key management only: roll_for_next_slot, next_enc_key,
    current_dec_key)
  • ShieldApi runtime API definition (try_decode_shielded_tx, try_unshield_tx)
  • Inherent identifier, ShieldPublicKey type, logging target

stc-shield (new subtensor client crate)

Node-side shield logic:

  • MemoryShieldKeystore — in-memory ML-KEM keystore implementation (key generation and storage
    only; no crypto operations — those now run in WASM)
  • InherentDataProvider — provides the next encapsulation (public) key as an inherent
  • spawn_key_rotation_on_own_import — rotates ML-KEM keypairs when the validator imports its own
    block

sc-basic-authorship (block proposer)

  • ProposerFactory / Proposer accept a ShieldKeystorePtr for key access
  • Shielded transactions are detected via the ShieldApi runtime call
  • The proposer reads the raw decapsulation key bytes from the keystore and passes them to the
    runtime's try_unshield_tx, which performs ML-KEM-768 decapsulation and XChaCha20-Poly1305 AEAD
    decryption entirely in WASM
  • Both the wrapper and the decrypted inner extrinsic are pushed into the produced block
  • Block size estimation accounts for wrapper + estimated inner transaction size
  • Validators can opt out via SUBSTRATE_SKIP_SHIELDED_TXS=1 — skipped transactions stay in the
    pool for gossip to other authors
  • Refactored report_exhausted_resources helper shared between normal and unshielded tx paths

sp-runtime (minor)

  • Add fn call() to the Applyable trait (needed to inspect the call after signature check)

pallet-aura (minor)

  • Make current_slot_from_digests public for shield key rotation

substrate-test-runtime

  • Implement ShieldApi using storage keys (Wasm-compatible) for proposer tests

Architecture

All cryptographic operations (ML-KEM-768 decapsulation, XChaCha20-Poly1305 decryption) run
entirely in WASM — no BLS12-381-style host function imports are needed. The node side is
responsible only for key generation, storage, and rotation; the raw decapsulation key bytes are
passed to the runtime API as a parameter.

Operation Runs in Details
Key generation & storage Node (stc-shield) MemoryShieldKeystore with ML-KEM-768
Key rotation Node (background task) Rolls keypairs on own block import
Public key announcement WASM (inherent) Pallet stores CurrentKey / NextKey
Shielded tx detection WASM (runtime API) try_decode_shielded_tx parses wrapper
ML-KEM decapsulation WASM (runtime API) try_unshield_tx — pure ml-kem crate
AEAD decryption WASM (runtime API) try_unshield_tx — pure chacha20poly1305 crate
Block building orchestration Node (proposer) Calls runtime API, pushes both txs

Tests

Screenshot 2026-03-02 at 12 29 29 PM

@sam0x17 sam0x17 merged commit 6a3ec6d into polkadot-stable2506-2-otf-patches Mar 2, 2026
134 of 227 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants