SIMD-0152

Precompiles

Author: Emanuele Cesena · Category: Core Protocol GitHub →

Feature Gate Status

Mainnet Active E714
Testnet Active E694
Devnet Active E791

ed9tNscbWLYBooxWA7FE2B5KHWs8A6sxfY8EzezEcoo

TL;DR

Define a unified behavior for precompiles, and highlight a few minor changes to the existing precompiles to minimize differences.

Summary

Define a unified behavior for precompiles, and highlight a few minor changes to the existing precompiles to minimize differences.

Motivation

Precompiles are special native programs designed to verify additional transaction signatures. They run without the VM and without loading any account, and they can access data from other instructions, within the same transaction. At the time of writing, two precompiles exist to verify Ed25519 and Ethereum-like Secp256k1 signatures, and another one is being proposed to support Secp256r1 signatures for FIDO Passkeys. Historically, the two precompiles were built at different times and by different people, so naturally there are some subtle differences in how they behave, especially in edge cases. The main goal of this document is to provide a specification for how a precompile should behave, remove differences and provide guidelines for future proposals. In addition, we highlight 3 minor changes to the existing precompiles that will simplify their behavior and make it easier to develop alternative validator clients.

Key Changes

  • If instruction data is empty, return error.
  • The first byte of data is the number of signatures num_signatures.
  • If num_signatures is 0, return error.
  • Expect (enough bytes of data for) num_signatures instances of PrecompileOffsets.
  • For each signature: a. Read offsets: an instance of PrecompileOffsets b. Based on the offsets, retrieve signature, public_key, and message bytes. If any of the three fails, return error. c. Invoke the actual sigverify function. If it fails, return error.
  • Get the instruction_index-th instruction_data
  • The special value 0xFFFF means "current instruction"
  • If the index is invalid, return Error
  • Return length bytes starting from offset
  • If this exceeds the instruction_data length, return Error
  • Change #1. Replace sigverify function with Dalek strict_verify(), the same used for transactions sigverify.
  • Change #2. Implement step 3 above: "If num_signatures is 0, return error."
  • Q: Why does the Ed25199 precompile currently use verify instead of strict_verify? A: No good reason, it was built without noticing the difference.
  • Q: If we switch to strict_verify, will some of the existing signatures break verification? A: All signatures created by a "regular" library, i.e. following RFC, pass both verify and strict_verify. Only carefully crafted signatures can pass verify and not strict_verify. So this won't break any honest use case.
  • Q: Why not leaving it as is? A: The verify is not well specified. In fact, it's behavior is slightly different in the older version of Dalek that Solana currently uses, versus the latest version of the same library. Trying to replicate all the edge cases is different validators is an unnecessary effort, not worth the risk of exposing different behaviors.
  • Change #3. Implement step 3 above: "If num_signatures is 0, return error."

Impact

Reduce the complexity of existing precompiles, to simplify building different validator clients.

Backwards Compatibility

All 3 changes require a feature gate.

Security Considerations

All 3 changes are straightforward and have no impact on security.