Skip to main content

0010. Keep go-ethereum for EIP-712 and secp256k1 signing

  • Status: Proposed
  • Date: 2026-09-30

Context

The backend signs two kinds of typed data for Polymarket: ClobAuth for L1 auth (Phase 2) and CLOB orders for the CTF and Neg Risk exchanges, wrapped in the Deposit Wallet’s ERC-7739 TypedDataSign and the Session Key wrapper (Phase 3, venue notes §4 and §10). Phase 2 uses github.com/ethereum/go-ethereum v1.17.6 for this. The Phase 2 security review (finding P2-10) noted that the go-ethereum surface is large for what it does. signer/core/apitypes pulls in core/types, kzg4844, params and more to hash one struct. With CGO off it uses the pure-Go decred secp256k1 code; a CGO-on Linux build would compile C libraries instead. govulncheck was clean. The review asked for either a small EIP-712 encoder checked against the golden vectors, or an ADR accepting go-ethereum. The tech lead chose to keep it (PLAN Phase 3 decisions).

Decision

  • Keep go-ethereum for EIP-712 hashing and secp256k1 signing.
  • The packages used are: Phase 3 adds the order and TypedDataSign hashing in the same package; whether it uses apitypes or crypto directly is defined by implementation.
  • All EIP-712 and signing code stays in venue/polymarket/signing (CLAUDE.md). Other packages import only the common types and, in app, address derivation.
  • Byte-for-byte golden vectors from the official SDK stay the acceptance test for every hash and signature, whatever library computes them.
  • From Phase 6, every build runs with CGO_ENABLED=0: the Docker image, task build and CI. go-ethereum then always uses its pure-Go secp256k1, and the binary has no C dependencies.

Consequences

  • No new cryptographic code to write or review. go-ethereum’s EIP-712 encoder is widely used and already matches all ClobAuth vectors.
  • The dependency tree is large. govulncheck and osv-scanner run on every lint; a finding in go-ethereum is triaged like any other, and most of its packages are never called.
  • Binary size and build time are higher than a small encoder would give. Both are acceptable for a single server binary.
  • Upgrading go-ethereum is a signing change: it needs the security review and the golden vectors to pass.

Alternatives considered

  • A small EIP-712 encoder in signing (about 200 lines: type string, encodeData, domain separator), with golang.org/x/crypto/sha3 for Keccak and decred/dcrd/dcrec/secp256k1 for signing. Rejected for now. It removes most of the dependency tree but adds hand-written cryptographic encoding, including the nested TypedDataSign type, to a path where a bug costs money. The golden vectors would catch errors in the cases they cover, not in the cases they do not. The review can reopen this if go-ethereum causes a vulnerability or build problem.
  • Only the go-ethereum crypto package, with a hand-written encoder. Rejected for the same reason: the encoder is the part with the most room for error, and crypto alone is not what makes the dependency large.