ml_dsa_65 to the accepted consensus key types: on a new chain through genesis, or on a live chain through a governance proposal, with no coordinated restart.
For background on ML-DSA and the key types, see Post-quantum keys.
Before any validator rotates to an ML-DSA key, every counterparty chain that verifies this chain over IBC must run CometBFT v0.40 or later. See IBC considerations.
Prerequisites
- The chain runs Cosmos SDK 0.55 and CometBFT 0.40 or later. See the release notes.
- jq and curl. The commands derive the proposal payload with jq and read the validator set with curl.
- The chain’s CLI binary on your PATH, with RPC access to a node. To stand up a local chain, see Run a node.
- For a live chain: the ability to pass a governance proposal, and an account funded for the proposal deposit and gas.
simd; substitute your chain’s binary, and adjust key names and denoms to your own.
Check the current state
Consensus params list the allowed key types undervalidator.pub_key_types. Query them:
ed25519 only. To see which types the validator set is currently running, list the validators and read each one’s pubkey type:
tendermint/PubKeyEd25519 for ed25519 keys, cometbft/PubKeyMlDsa65 for ML-DSA keys.
New chain: set the types in genesis
Addml_dsa_65 to consensus.params.validator.pub_key_types in genesis.json before launch:
ed25519 in the list unless every genesis validator starts on an ML-DSA key. Validators whose key type is not in the list cannot join the set. A genesis validator starts on an ML-DSA key by initializing its node with simd init <moniker> --consensus-key-algo ml_dsa_65, and a local ML-DSA testnet comes from the same flag on simd testnet init-files or simd testnet start.
Live chain: expand the types through governance
The change is a parameter update executed by governance. It takes effect when the proposal passes, with no node restarts and no coordinated upgrade. All steps read and writeparams.json in the current directory, so run them from one place.
- Build the proposal params from the live chain state. The update message replaces the entire params object, so it must carry every current value. The following command derives the params from a query, adds
ml_dsa_65topub_key_types, and converts the evidence duration to the format the proposal parser accepts:
- You can then submit the file’s contents as a governance proposal. The command takes the four param groups as separate arguments, sliced from the same file. Make sure to update the following command to include your key and correct deposit amount/denomination. Add
--homepointing at your node’s home, since the transaction commands on this page read the keyring from it. Also add--chain-idand--keyring-backendif your client config does not supply them, and--fees(or--gas-prices) to meet the chain’s minimum gas price:
- Vote as with any governance proposal, using the proposal ID from
simd query gov proposals.
Verify
Query the params again and confirm the list includesml_dsa_65:
Remove a key type
To remove a key type, update theparams.json file to remove the key type from the pub_key_types array. Then, submit the updated params.json file as a governance proposal.
Do not remove a key type while validators still use it. Existing validators are not re-checked when a type leaves the list, but every later voting-power update for such a validator fails validation, and a failed validator update halts the chain. Routine activity is enough to trigger it: any delegation that changes the validator’s voting power emits one of these updates.
Next steps
- Understand the rotation mechanics before touching a production validator. See Key rotation.
- Migrate a validator to the new key type. See Migrate a validator to ML-DSA.