Skip to content

feat(evm): add Ed25519 signature-verify precompile at 0x403 - #393

Open
sfffaaa wants to merge 1 commit into
feature/blk-1007-precompile-p256from
feature/blk-1008-precompile-ed25519
Open

feat(evm): add Ed25519 signature-verify precompile at 0x403#393
sfffaaa wants to merge 1 commit into
feature/blk-1007-precompile-p256from
feature/blk-1008-precompile-ed25519

Conversation

@sfffaaa

@sfffaaa sfffaaa commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a native EVM precompile for Ed25519 (RFC 8032) signature verification at address 0x403, flat 3,000 gas. Ed25519 is the scheme used by Substrate/Polkadot accounts, Solana and many off-chain systems; the EVM cannot verify it natively, which blocks cross-ecosystem attestations and Substrate-key-to-EVM identity proofs at reasonable cost.

Stacked on the P256VERIFY PR (#392) — this diff contains only the Ed25519 changes.

Interface

Address 0x0000000000000000000000000000000000000403 (peaq-specific, see below)
Input 128 bytes: message(32) ‖ publicKey(32) ‖ signature(64) — exact length, message is NOT pre-hashed
Output 32-byte 1 if valid; empty if invalid/malformed; never reverts
Gas 3,000 flat

Two deliberate decisions (reviewer attention)

Address is peaq-specific. Ed25519 has no adopted precompile-address standard: EIP-665 proposed 0x9 but was never activated (that slot is now Blake2F), and chains that added Ed25519 each picked their own (Celo 0xF3, Bittensor 0x402). 0x403 is the next free slot in peaq's non-Ethereum range (0x400 Sha3FIPS256, 0x402 ECRecoverPublicKey). Integrators must hardcode it for peaq only — needs to be explicit in docs.

Output convention matches P256VERIFY, not the upstream Frontier implementation this is vendored from. One check — out.length == 32 && out[31] == 1 — works for both signature precompiles. Vendoring is required because the upstream gas constants are compile-time and cannot be overridden from wiring; the upstream default (base 15 + 3/word) underprices an Ed25519 verify ~100×, a block-time DoS vector, hence the flat 3,000 matching ecrecover's pricing for comparable EC work.

Security notes

Standard RFC 8032 verification via ed25519-dalek 2.1.0: non-canonical s rejected (classic malleability blocked); small-order public keys accepted — the calling contract must treat the key as a binding it already trusts; replay protection and domain separation are the caller's responsibility. Wrong-length input (including trailing bytes) is rejected as invalid, never a revert.

Changes

New crate precompiles/ed25519 (no_std, adapted from Frontier), wired into peaq, peaq-dev and krest runtimes; callable by contracts and precompiles.

Testing

  • Crate unit tests; all three runtimes compile at this commit.
  • End-to-end against a live dev network built from this branch: valid signature → 0x…01; flipped message bit, truncated, oversized and empty inputs → empty output, no revert. Suite in peaq-bc-test branch feature/sig-precompile-tests.

@sfffaaa
sfffaaa force-pushed the feature/blk-1007-precompile-p256 branch from d802023 to 2ecf8ad Compare August 18, 2026 11:03
@sfffaaa
sfffaaa force-pushed the feature/blk-1008-precompile-ed25519 branch from 7d5c022 to dc5472c Compare August 18, 2026 11:03
On-chain Ed25519 signature verification in the EVM -- verifying Substrate,
Solana, and other Ed25519 / off-chain-signed data on-chain.

- New crate pallet-evm-precompile-ed25519, vendored from Frontier
  (ed25519-dalek 2.1, RFC 8032, no_std).
- Registered at address 0x403 (peaq-specific: Ed25519 has no ecosystem
  address standard -- EIP-665 was never activated) on peaq/peaq-dev/krest.
- Gas set to a flat 3000 (ecrecover parity) instead of Frontier's
  BASE=15/WORD=3, which underpriced the verify ~100x (block-time DoS).
- Output aligned with P256VERIFY / RIP-7212 instead of Frontier's 4-byte
  0-means-valid convention: a 32-byte big-endian 1 when valid, empty output
  otherwise, never reverts; input must be exactly 128 bytes. One output
  convention covers both signature precompiles.

Additive only: new precompile at a previously-unused address; no storage
migration and no change to existing precompiles. spec_version is left for
the release process to bump.
@sfffaaa
sfffaaa force-pushed the feature/blk-1007-precompile-p256 branch from 2ecf8ad to cc4d135 Compare August 18, 2026 14:01
@sfffaaa
sfffaaa force-pushed the feature/blk-1008-precompile-ed25519 branch from dc5472c to c45282e Compare August 18, 2026 14:01
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