precompile: gate every classical Run() via contract.RefuseUnderStrictPQ

Decomplect: profile-gating logic stays in one place (contract.RefuseUnderStrictPQ);
each classical precompile calls it once at the top of Run() and otherwise stays in
its lane. Quasar/P3Q/Pulsar/ML-KEM/ML-DSA/SLH-DSA/Corona/X-Wing/FHE precompiles
are post-quantum and skip the gate.

Wired into:
  bls12381 (7 EIP-2537 ops: G1/G2 add/mul/MSM + pairing)
  ed25519 (signature verify)
  cggmp21 (ECDSA threshold)
  frost (Schnorr threshold)
  ring (LSAG classical schemes; lattice scheme stays open)
  vrf (ECVRF EDWARDS25519)
  sr25519 (Schnorrkel/Ristretto255)
  x25519 (DH)
  curve25519 (raw Edwards25519 ops)
  hpke (classical KEMs; Kyber/X-Wing hybrid stays open)
  blake3 (classical hash)
  poseidon (BN254 algebraic hash)

Already gated upstream: kzg4844, zk (classical opcodes), babyjubjub, pedersen, pasta.

secp256r1 uses the non-stateful Run([]byte) interface (EIP-7212 standard).
Gating that precompile requires hooking the geth EVM precompile overrider, not
this package -- left for the LuxPrecompileOverrider follow-up.

Tests pass across all twelve gated dirs plus contract/.
This commit is contained in:
Hanzo AI
2026-05-11 15:03:39 -07:00
parent 9055365341
commit be53c4e9a3
12 changed files with 70 additions and 0 deletions
+3
View File
@@ -142,6 +142,9 @@ func (p *blake3Precompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
if len(input) < 1 {
return nil, remainingGas, ErrInvalidInput
+21
View File
@@ -98,6 +98,9 @@ func (p *g1AddPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g1Add(input, suppliedGas)
}
@@ -111,6 +114,9 @@ func (p *g1MulPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g1Mul(input, suppliedGas)
}
@@ -124,6 +130,9 @@ func (p *g1MSMPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g1MSM(input, suppliedGas)
}
@@ -137,6 +146,9 @@ func (p *g2AddPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g2Add(input, suppliedGas)
}
@@ -150,6 +162,9 @@ func (p *g2MulPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g2Mul(input, suppliedGas)
}
@@ -163,6 +178,9 @@ func (p *g2MSMPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.g2MSM(input, suppliedGas)
}
@@ -176,6 +194,9 @@ func (p *pairingPrecompile) Run(
suppliedGas uint64,
readOnly bool,
) ([]byte, uint64, error) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, suppliedGas, err
}
return blsOps.pairing(input, suppliedGas)
}
+3
View File
@@ -88,6 +88,9 @@ func (p *cggmp21VerifyPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
// Input format:
// [0:4] = threshold t (uint32)
+3
View File
@@ -93,6 +93,9 @@ func (p *curve25519Precompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, gas, err
}
if len(input) < 1 {
return nil, gas, ErrInvalidInput
}
+3
View File
@@ -81,6 +81,9 @@ func (c *ed25519VerifyPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
if len(input) != InputLength {
return nil, remainingGas, nil
+3
View File
@@ -91,6 +91,9 @@ func (p *frostVerifyPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
// Input format:
// [0:4] = threshold t (uint32)
+12
View File
@@ -191,6 +191,18 @@ func (p *hpkePrecompile) Run(
op := input[0]
// Classical KEMs (P256/P384/P521/X25519) are gated by the chain's
// strict-PQ profile. Hybrid PQ KEMs (X25519+Kyber768, X-Wing) carry
// a lattice component and remain open on every chain.
if op == OpSingleShotSeal && len(input) >= 3 {
kemID := uint16(input[1])<<8 | uint16(input[2])
if !isKyberKEM(kemID) {
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
}
}
var result []byte
switch op {
+3
View File
@@ -88,6 +88,9 @@ func (p *poseidonPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, gas, err
}
if len(input) < 1 {
return nil, gas, ErrInvalidInput
}
+10
View File
@@ -137,6 +137,16 @@ func (p *ringSignaturePrecompile) Run(
op := input[0]
scheme := input[1]
// Classical LSAG schemes (secp256k1, Ed25519, DualRing) are gated by
// the chain's strict-PQ profile. The lattice scheme (SchemeLatticeLSAG)
// remains open on every chain.
switch scheme {
case SchemeLSAGSecp256k1, SchemeLSAGEd25519, SchemeDualRing:
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
}
var result []byte
switch op {
+3
View File
@@ -96,6 +96,9 @@ func (p *sr25519VerifyPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
if len(input) < MinInputSize {
return failResult, remainingGas, fmt.Errorf(
+3
View File
@@ -109,6 +109,9 @@ func (p *vrfPrecompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, remainingGas, err
}
if len(input) < 1 {
return nil, remainingGas, nil
+3
View File
@@ -82,6 +82,9 @@ func (p *x25519Precompile) Run(
if err != nil {
return nil, 0, err
}
if err := contract.RefuseUnderStrictPQ(accessibleState); err != nil {
return nil, gas, err
}
if len(input) < 1 {
return nil, gas, ErrInvalidInput
}