Skip to content

chore(crypto): rename the well-known network keys for what they are - #262

Merged
samlaf merged 1 commit into
seismicfrom
sl/sei-172-chore-rename-the-well-known-keys-in-seismic-crypto-and
Aug 20, 2026
Merged

chore(crypto): rename the well-known network keys for what they are#262
samlaf merged 1 commit into
seismicfrom
sl/sei-172-chore-rename-the-well-known-keys-in-seismic-crypto-and

Conversation

@samlaf

@samlaf samlaf commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Part of SEI-172

The sample-key getters — get_unsecure_sample_secp256k1_sk/pk and get_unsecure_sample_schnorrkel_keypair — named these keys as test fixtures. They are not: every network with no root key to derive purpose keys from (dev networks and pre-TEE deployments, the live testnet included) runs them as its real network keys. Rename them for what they are, and document them plainly: published in this public repository, no confidentiality against anyone who reads the source; their only property is that every node and client agrees on them.

  • well_known_tx_io_keypair() replaces the secp256k1 sk/pk pair. One function, not two: the public half is derived from the secret half, so pair consistency holds by construction, and a test freezes the published public key against drift.
  • well_known_rng_ikm() -> [u8; 64] replaces the schnorrkel-keypair getter. Every consumer narrows the keypair to secret.to_bytes() and feeds the result to HKDF, so the function returns those 64 bytes directly, written in hex to compare easily against key material in logs. A dev-dependency test recomputes the original schnorrkel expansion and pins the bytes: the value is a consensus input via the RNG precompile, so it must never drift.
  • get_unsecure_sample_aesgcm_key and the SchnorrkelKeypair re-export are deleted; neither has a caller anywhere.

With the expansion out of production code, schnorrkel drops to a dev-dependency and leaves every consumer's transitive graph. Consumers pin this crate by git rev, so they take the rename when they bump.

Part of SEI-172

The sample-key getters — get_unsecure_sample_secp256k1_sk/pk and
get_unsecure_sample_schnorrkel_keypair — named these keys as test
fixtures. They are not: every network with no root key to derive
purpose keys from (dev networks and pre-TEE deployments, the live
testnet included) runs them as its real network keys. Rename them for
what they are, and document them plainly: published in this public
repository, no confidentiality against anyone who reads the source;
their only property is that every node and client agrees on them.

- well_known_tx_io_keypair() replaces the secp256k1 sk/pk pair. One
  function, not two: the public half is derived from the secret half,
  so pair consistency holds by construction, and a test freezes the
  published public key against drift.
- well_known_rng_ikm() -> [u8; 64] replaces the schnorrkel-keypair
  getter. Every consumer narrows the keypair to secret.to_bytes() and
  feeds the result to HKDF, so the function returns those 64 bytes
  directly, written in hex to compare easily against key material in
  logs. A dev-dependency test recomputes the original schnorrkel
  expansion and pins the bytes: the value is a consensus input via the
  RNG precompile, so it must never drift.
- get_unsecure_sample_aesgcm_key and the SchnorrkelKeypair re-export
  are deleted; neither has a caller anywhere.

With the expansion out of production code, schnorrkel drops to a
dev-dependency and leaves every consumer's transitive graph. Consumers
pin this crate by git rev, so they take the rename when they bump.
@samlaf
samlaf requested a review from cdrappi as a code owner August 20, 2026 16:33
@linear-code

linear-code Bot commented Aug 20, 2026

Copy link
Copy Markdown

SEI-172

@samlaf
samlaf merged commit 7dc159d into seismic Aug 20, 2026
5 checks passed
@samlaf
samlaf deleted the sl/sei-172-chore-rename-the-well-known-keys-in-seismic-crypto-and branch August 20, 2026 16:46
samlaf added a commit to SeismicSystems/seismic-revm that referenced this pull request Aug 20, 2026
…239)

Part of SEI-172

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs, not test fixtures. The RNG tests here
take the rename: well_known_rng_ikm() returns the 64 ikm bytes directly,
which every call site already narrowed the schnorrkel keypair down to.
The bytes are identical, so the pinned RNG-precompile outputs
(consensus-visible) are unchanged.

- schnorrkel is now a dev-dependency of seismic-crypto, so it and its
curve25519-dalek subtree leave this crate's dependency graph.
- RootRng::test_default() is deleted. It was public API with no callers
outside this crate's own tests, and hid which key the tests pin; the
tests construct RootRng::new(well_known_rng_ikm()) directly.
samlaf added a commit to SeismicSystems/seismic-alloy that referenced this pull request Aug 20, 2026
…4f (well-known key rename)

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs, not test fixtures. The tests here take
the rename: well_known_tx_io_keypair() replaces the split sk/pk getters,
so a mismatched pair is unrepresentable, and the tee-pubkey test still
matches the key sanvil serves — the values are unchanged.

The seismic-revm pin moves to the rev that takes the same rename
(SeismicSystems/seismic-revm#239): the [patch.crates-io] seismic-crypto
override applies to seismic-revm's build too, so both pins advance
together.

Part of SEI-172
samlaf added a commit to SeismicSystems/seismic-alloy that referenced this pull request Aug 20, 2026
…ame) (#113)

Part of SEI-172

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs, not test fixtures. The tests here take
the rename: well_known_tx_io_keypair() replaces the split sk/pk getters,
so a mismatched pair is unrepresentable, and the tee-pubkey test still
matches the key sanvil serves — the values are unchanged.

The seismic-revm pin moves to the rev that takes the same rename
(SeismicSystems/seismic-revm#239): the [patch.crates-io] seismic-crypto
override applies to seismic-revm's build too, so both pins advance
together.
samlaf added a commit to SeismicSystems/seismic-evm that referenced this pull request Aug 20, 2026
…ypair (#65)

Part of SEI-172

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs, not test fixtures. The revm and alloy
pins move to the revs that take the same rename
(SeismicSystems/seismic-revm#239, SeismicSystems/seismic-alloy#113).

PurposeKeys holds the tx-io pair as one secp256k1::Keypair, so a
mismatched pair is unrepresentable everywhere the struct travels; call
sites read .secret_key() / .public_key(), and the redacting Debug prints
tx_io.public_key(). PurposeKeys::well_known() names the bundle a network
with no root key runs, in the crate that owns the type — one definition
for the node's built-in key source and for every test that needs a
bundle a node would accept. Its dependency costs nothing: seismic-crypto
is already in this crate's graph through both seismic-revm and
seismic-alloy-consensus.

The alloy-tx-macros tag patch goes away: seismic-alloy exact-pins it at
=1.1.0 in the crate that introduces the edge, and version requirements
propagate where patches do not. Cargo.lock is committed so CI stops
resolving fresh and picking up releases inside caret ranges that
conflict with the pinned alloy-core fork.
samlaf added a commit to SeismicSystems/seismic-foundry that referenced this pull request Aug 20, 2026
…223)

Part of SEI-172

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs, not test fixtures. sanvil serves the
well-known tx-io public key from seismic_getTeePublicKey and decrypts
calldata with the secret half, so every call site here takes the rename.
The key values are unchanged.

The seismic-revm and seismic-alloy pins move to the revs carrying the
same rename (SeismicSystems/seismic-revm#239,
SeismicSystems/seismic-alloy#113). The alloy-evm pin stays where it is:
nothing here builds a PurposeKeys, and the newer revs rename
alloy_evm::overrides::StateOverrideError, which anvil's error module
imports.

seismic-alloy exact-pins alloy-chains at =0.2.34 so the constraint
reaches its consumers, which moves this lock from 0.2.25 to 0.2.34.
alloy-chains replaced EtherlinkTestnet (128123) with EtherlinkShadownet
(127823) in that range, so the different-gas-calc chain list names the
Etherlink test network that crate now knows.
samlaf added a commit to SeismicSystems/seismic-reth that referenced this pull request Aug 20, 2026
… copy (#482)

Fixes SEI-172

seismic-crypto renamed its well-known network key getters for what they
are (SeismicSystems/enclave#262): these are the keys every network
without a root key actually runs — the live testnet included, via
`--seismic.purpose-keys-source built-in` — not test fixtures.
seismic-evm now owns the bundle built from them: PurposeKeys holds the
tx-io pair as one secp256k1::Keypair, and PurposeKeys::well_known() is
the single definition of what a network with no root key boots on
(SeismicSystems/seismic-evm#65). The revm and alloy pins move to the
revs carrying the same rename (SeismicSystems/seismic-revm#239,
SeismicSystems/seismic-alloy#113).

So this repo's second copy goes away: the two hex literals,
WELL_KNOWN_RNG_IKM, and the well_known_purpose_keys() wrapper are gone,
and the built-in key source returns PurposeKeys::well_known() directly,
keeping the note on what those keys mean for a pre-TEE network. Two
tests go with them: one asserted our copy equalled seismic-crypto's,
which is now a tautology, and one asserted the hardcoded public key was
the secret key's, which the Keypair makes structural. The four mock
bundles (node test utils, fuzz targets, the evm unit tests, the hardfork
e2e test) call the same constructor, so every key value they use is
unchanged.

Elsewhere the tx-io pair is read through the keypair: the rpc extension
serves tx_io.public_key() and encrypts and decrypts with
tx_io.secret_key(). The custodian decode keeps its wire-level
cross-check of the served pair and then builds the Keypair from the
secret half; the IPC contract is untouched.

schnorrkel leaves the repo along with the derivation that needed it. The
rng ikm is HKDF input material that no schnorrkel cryptography ever
touched, and seismic-crypto now returns those same bytes as a frozen
constant.
samlaf added a commit that referenced this pull request Aug 21, 2026
Part of SEI-222

get_rng_ikm derived its 64 bytes as HKDF(root_key) -> MiniSecretKey ->
expand(Uniform) -> secret bytes. The schnorrkel step is a leftover of
the original VRF-based RNG design: no schnorrkel cryptography is
performed with the result, and every consumer already narrows it to a
raw [u8; 64]. It now takes those 64 bytes from the purpose derivation
itself.

This changes the rng key on every network that has a root key, and
RNG-precompile outputs are consensus, so re-found any running TEE devnet
across the change rather than upgrading it in place. A network with no
root key runs the well-known ikm literal (#262) and never reaches this
derivation; the live testnet is one of those and is unaffected.

expand_purpose<const N> is now the crate's only deriver: 32 bytes for
every purpose, 64 for RngPrecompile. That retires the last schnorrkel
use in production code, so the crate drops the dependency and schnorrkel
stays only as seismic-crypto's dev-dependency, without the serde feature
nothing asked for.

The derivation also stops being public API. Key, KeyPurpose and
derive_purpose_key leave the crate's surface, which is now exactly one
way out per defined key: get_tx_io_sk, get_tx_io_pk, get_rng_ikm and
get_snapshot_key hand a caller its key in that key's own type, and
write_luks_keyfile exports the LUKS pair, whose bytes no in-process
caller ever holds. Nothing outside the crate imported the removed items.

Two things fall out of that:

- Key had one job left, scrubbing root_key, and that needs no named
type: Custodian derives ZeroizeOnDrop over a plain [u8; 32]. The vacuous
Result on derive_purpose_key, its .expect at three call sites, and
get_snapshot_key's length try_into go with it.
- write_luks_keyfile assembles both LUKS keys into one buffer that
leaves as a file. The buffer is now Zeroizing, so the copy this process
keeps is scrubbed once the write lands.
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.

1 participant