Сервисы на Go, которые работают с подписями Ethereum, обычно импортируют github.com/ethereum/go-ethereum/crypto и accounts. При включённом cgo пакет использует копию libsecp256k1, которая поставляется в составе go-ethereum, а при CGO_ENABLED=0 переключается на реализацию decred на чистом Go. Проверка прогнала обе сборки, и все факты совпали.
crypto.Sign(hash, key) принимает ровно 32 байта (иначе возвращает ошибку hash is required to be exactly 32 bytes), ничего не хеширует и не добавляет префикс. Сообщение для входа сначала нужно пропустить через accounts.TextHash: эта функция добавляет префикс EIP-191 и хеширует результат keccak-256, что проверка подтвердила сравнением с независимой реализацией keccak. Если вместо этого подписать голый keccak сообщения, получится подпись, которая никогда не совпадёт с подписями ethers, viem и кошельков.
Подпись занимает 65 байт, а идентификатор восстановления записан в v как 0 или 1, тогда как кошельки, ethers, viem и web3.py ставят туда 27 или 28. crypto.Ecrecover отклонил v = 27/28 с ошибкой invalid signature recovery id, поэтому на входе вычитайте 27, а на выходе прибавляйте его обратно, как это делает пример. Nonce вычисляются по RFC 6979 (подпись совпала с независимой эталонной реализацией), а s всегда находится в нижней половине диапазона.
Два пути проверки расходятся в отношении high-S. crypto.VerifySignature, который принимает 64 байта без v, отклонил зеркальную подпись (r, n − s), а crypto.Ecrecover и crypto.SigToPub восстановили по ней правильный открытый ключ — так же, как прекомпилированный контракт ecrecover в EVM. Поэтому контракты и сервисы, которые восстанавливают адреса, должны сами отклонять high-S, если используют подпись как уникальный идентификатор.
Открытые ключи передаются как несжатые точки SEC1 длиной 65 байт или сжатые точки длиной 33 байта, а закрытые ключи — как 32-байтовые скаляры. Чтобы понять, какому соглашению следует подпись, вставьте её в проверку подписей Ethereum; повторы nonce в транзакциях одного адреса выявит проверка повторного использования nonce в Ethereum.