Skip to content
PQC Migration Guide · Solidity · 2025

How to migrate your Solidity contracts to post-quantum cryptography

QuantumScan detected the vulnerability. Here is the concrete migration path for every pattern — from today's audit to the long-term quantum-safe architecture.

← Back to Solidity scanner
Real scan proof: OpenZeppelin core contracts100/100 Critical
$ npx quantumscan ./openzeppelin-contracts/contracts/token/ERC20/extensions/
QuantumScan v1.5.0 · Post-Quantum Cryptography Scanner
🟠 HIGH18 findings
ECDSA.sol:190 · ecrecover(
EIP712.sol:109 · _hashTypedDataV4(
ERC20Permit.sol:57 · _hashTypedDataV4(
... 15 more findings
Risk Score 100/100 Critical 🚨

These are the contracts that 80%+ of DeFi protocols inherit. Every token using ERC20Permit is affected.

Migration timeline

Now — Audit

Run QuantumScan. Document every ecrecover(), EIP-712, and permit() usage. Add findings to your audit report.

2025-2027 — Hybrid

Deploy Account Abstraction (ERC-4337) wrappers with ML-DSA support alongside existing ECDSA. Dual-sign critical operations.

2028-2030 — Migrate

NIST/CNSA 2.0 deadline. Replace ECDSA signers with ML-DSA (FIPS 204). Ethereum expected to have PQC precompile by then.

Migration path by pattern

ecrecover() / ECDSA.recover()Medium term@noble/post-quantum
1. Freeze

Stop adding new ecrecover() calls to contracts. Document all existing usages.

2. Wrap with ERC-4337

Deploy a Smart Account (ERC-4337) with a custom signature validator. The validator can support ML-DSA (CRYSTALS-Dilithium) signatures off-chain verified on-chain.

// ERC-4337 custom validator — replace ecrecover
function validateUserOp(UserOperation calldata op, bytes32 hash, uint256 missingFunds)
  external returns (uint256) {
    // verify ML-DSA signature instead of ECDSA
    require(mlDsaVerify(hash, op.signature, ownerPubKey), "Invalid PQC sig");
    return 0;
}
3. Use @noble/post-quantum

Off-chain: generate ML-DSA key pairs and sign with @noble/post-quantum. On-chain: verify via custom precompile or ZK proof.

import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
const keys = ml_dsa65.keygen();
const sig = ml_dsa65.sign(keys.secretKey, message);
const valid = ml_dsa65.verify(keys.publicKey, message, sig);
EIP-712 typed data signaturesMedium term
1. Document domain separators

Map every EIP712Domain in your codebase. These are the migration targets.

2. Hybrid signing

Add a parallel ML-DSA signature field to your typed data structs. Verify both ECDSA and ML-DSA. Accept only ML-DSA once quantum computers become a real threat.

struct PermitWithPQC {
  address owner;
  address spender;
  uint256 value;
  uint256 deadline;
  bytes   ecdsaSig;   // legacy — remove post-migration
  bytes   mlDsaSig;  // ML-DSA FIPS 204 — quantum-safe
}
3. Wait for PQC EIP

No PQC EIP-712 standard exists yet. Monitor EIPs on ethereum/EIPs. The hybrid approach above is the interim path.

Assembly ecrecover precompile (0x1)Short term first step
1. Replace assembly with library

Assembly-level ecrecover calls are harder to audit and migrate. First refactor to ECDSA.recover() from OpenZeppelin — same vulnerability, but much easier to swap later.

// BEFORE (assembly — hard to migrate)
assembly {
  let success := staticcall(gas(), 0x1, ptr, 0x80, ptr, 0x20)
  signer := mload(ptr)
}

// AFTER (library — easy to replace with ML-DSA later)
address signer = ECDSA.recover(hash, v, r, s);
2. Then follow ecrecover() migration path

Apply the ERC-4337 ML-DSA migration path from the ecrecover pattern above.

Chainlink oracle (secp256k1 DON)Long term — depends on Chainlink
1. Monitor Chainlink PQC roadmap

Chainlink DON threshold ECDSA migration is outside your control. Monitor their public roadmap. No PQC Chainlink interface exists today.

2. Add circuit breaker

Deploy an oracle circuit breaker that can freeze price updates if the oracle is compromised. This limits blast radius during a quantum attack window.

// Circuit breaker — freeze if oracle is flagged
modifier oracleNotFrozen() {
  require(!oracleFrozen, "Oracle frozen: quantum risk flag active");
  _;
}
3. Multi-oracle fallback

Use a median of multiple oracle sources (Chainlink + Pyth + UMA). If any one is compromised, the median prevents manipulation.

ERC-2612 permit() gasless approvalsShort term
1. Add emergency disable

Add a guardian function to disable permit() if a quantum threat becomes active. Classic approve() is not quantum-safe either, but removes the off-chain signature vector.

bool public permitEnabled = true;

function setPermitEnabled(bool enabled) external onlyOwner {
  permitEnabled = enabled;
  emit PermitStatusChanged(enabled);
}

function permit(...) public override {
  require(permitEnabled, "permit() disabled: PQC migration in progress");
  super.permit(...);
}
2. Migrate to ERC-4337 permit

Replace ERC-2612 permit with an ERC-4337 user operation that uses ML-DSA signature. No ERC standard exists yet — track EIP proposals.

Gnosis Safe / MultiSig N-of-M ECDSAMedium term
1. Key rotation plan

Document all current signer addresses. Plan rotation schedule — replace existing secp256k1 signers with PQC signers using Safe's owner management functions.

2. Deploy Safe Module for PQC

Safe supports custom modules. Deploy a PQC Safe Module that verifies ML-DSA signatures as an additional signer type, without replacing ECDSA signers immediately.

// Safe PQC Module (conceptual)
contract PQCSafeModule is Module {
  mapping(address => bytes) public pqcPublicKeys; // ML-DSA pub keys

  function execPQCTransaction(
    address safe, address to, uint256 value,
    bytes calldata data, bytes calldata mlDsaSig
  ) external {
    require(mlDsaVerify(keccak256(data), mlDsaSig, pqcPublicKeys[msg.sender]));
    ISafe(safe).execTransactionFromModule(to, value, data, Enum.Operation.Call);
  }
}
3. Monitor Safe{Wallet} roadmap

Safe team is aware of the PQC migration need. Monitor github.com/safe-global/safe-contracts for PQC proposals.

PQC tools for Solidity developers

EIPs to watch

Final
EIP-4337

Account Abstraction — enables custom PQC signature validators. Live on mainnet.

Final
EIP-7702

Set EOA code — allows PQC key migration for regular wallets. Included in Pectra.

Draft
BIP-360

QuBit — P2QRH (Pay to Quantum Resistant Hash) for Bitcoin. Reference for Ethereum parallel.

Scan your contracts now

Get the full vulnerability report before starting your migration. Free, open-source, no account required.

← Back to home