Skip to content

Fix: veridise 801/825 refactor rng precompile#189

Open
daltoncoder wants to merge 8 commits intoveridise-audit-feb-2026from
fix--veridise-801-refactor-rng-precompile
Open

Fix: veridise 801/825 refactor rng precompile#189
daltoncoder wants to merge 8 commits intoveridise-audit-feb-2026from
fix--veridise-801-refactor-rng-precompile

Conversation

@daltoncoder
Copy link
Contributor

@daltoncoder daltoncoder commented Feb 16, 2026

This PR is to address Veradise Audit 801(Block proposers can bias precompile randomness) and Veridise Audit 825(System-call trait fallthrough bypasses Seismic RNG reset).

Both of these issues are based on the idea of the state of the Rng precompile being tampered with to get favored results on the Rng. After diving in i realized that despite the many leftover comments we left in the code, the Execution mode that is used is prod is actually stateless and not really susceptible to these state attacks.


What we had before this PR:

Two modes to start the precompile in;
SimulationMode => Uses a stateful Merlin Transcript that gets appended to everytime its used to generate range. The Merlin Transcript is then forked every call to provide a new RootRng key. The appended to Merlin Transcript is used for the next call which gives it state
ExecutionMode => What we use in production. This is stateless and derives random bytes via HKDF-SHA256 using a schnorrkel key that is received from the Enclave. HKDF parameters are the txn_hash and user provided personality_bytes. Same txn_hash and pers_bytes will yield the same random number.


What this PR changes:

  • Precompile is stateless in all code paths. Merlin Transcript code path removed. Even in simulation we will use HKDF + Snorrkel key. The only difference is we will generate a new ephemeral key every call with OsRng when in SimulationMode. This removed a lot of code and is much more clear.
  • We now salt with total_gas_left along with txn_hash and personality_bytes. This is not the typical gas_left() in solidity and is the total_gas_left across all frames in a transactions call. This is mainly to make it so a transaction that may re-enter certain functions will still get a random number each time. So in the context of a single transaction same personality_bytes and txn_hash will yield a different result. This required some changes to evm_handler and SeismicChain Context to get to work.

One side effect that this introduces is that now it is impossible to get the same output in a single transaction more than once. Before in Execution mode you could pass the same personality bytes in multiple times in a row within a single transaction and get the same output. Now that is not the case. I personally think that this more desirable behavior but let me know if anyone thinks otherwise.

@daltoncoder daltoncoder requested a review from cdrappi as a code owner February 16, 2026 19:54
@daltoncoder daltoncoder changed the title Fix veridise 801 refactor rng precompile Fix: veridise 801/825 refactor rng precompile Feb 16, 2026
chunk_idx += 1;
}
output.truncate(len);
output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

@daltoncoder daltoncoder force-pushed the fix--veridise-801-refactor-rng-precompile branch from 538552b to a0be18f Compare February 16, 2026 22:34
Copy link
Contributor

@samlaf samlaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like nice simplification! Didn't fully look at the RNG and gas calculation logic as its a bit over my head right now, so will rely on others for that. Mostly looked at interface. Few comments but overall LGTM!

Comment on lines +10 to +12
live_rng_key: Option<schnorrkel::Keypair>,
/// Total remaining gas across all active call frames, set before precompile dispatch.
gas_remaining_all_frames: u64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these 2 options are only for the rng precompiles right? Can we add this as a comment?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for example maybe good to also add something like "gas_remaining_all_frames is used to make different calls to the RNG precompile inside a tx return different results"?

Comment on lines +16 to +17
/// - **Simulation mode** (`live_key = None`): generates a random key via `OsRng`.
/// Non-deterministic by design (each call gets a fresh random key).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need this simulation mode at all? or could we just inject a random test execution key in tests and always use the "execution mode"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we discussed this offline and think you found a nice solution here already

pub struct SeismicChain {
rng_container: RngContainer,
live_rng_key: Option<schnorrkel::Keypair>,
/// Total remaining gas across all active call frames, set before precompile dispatch.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually its set in frame_init, which will run on any call/staticcall/create//delegatecall, not only to precompiles, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes if we wanted to access this in another precompile it would be there. Or expose an opcode for any transaction to read it we could

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.

3 participants