> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sesameterminal.com/llms.txt
> Use this file to discover all available pages before exploring further.

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

# 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](../venue/polymarket.md#4-deposit-wallet-order-signatures-signature-type-3-poly_1271)).
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:

  | Package | Used for | Where |
  | - | - | - |
  | `signer/core/apitypes` | EIP-712 typed data: domain separator, struct hash, digest | `venue/polymarket/signing` |
  | `crypto` | Keccak-256, secp256k1 signing, address from a key | `signing`, and `app/config.go` to derive the signer address for the owner-address check |
  | `common`, `common/hexutil`, `common/math` | Address and hex types, `HexOrDecimal256` for the chain id | `signing`, the Polymarket adapter, `app` |

  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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.