Go services that handle Ethereum signatures usually import github.com/ethereum/go-ethereum/crypto and accounts. With cgo enabled the package uses the libsecp256k1 copy vendored in go-ethereum; with CGO_ENABLED=0 it falls back to the pure-Go decred implementation — the check ran both builds and every fact came out identical.
crypto.Sign(hash, key) takes exactly 32 bytes (hash is required to be exactly 32 bytes otherwise) and does no hashing and no prefixing. A login message must go through accounts.TextHash first, which adds the EIP-191 prefix and hashes with keccak-256 — the check confirmed it against an independent keccak. Signing the bare keccak of the message instead produces a signature that ethers, viem and wallets will never match.
The signature is 65 bytes with the recovery id as v = 0 or 1, while wallets, ethers, viem and web3.py put 27 or 28 there. crypto.Ecrecover rejected v = 27/28 with invalid signature recovery id, so subtract 27 on the way in and add it on the way out, as the sample does. Nonces follow RFC 6979 — the signature matched an independent reference implementation — and s is always low.
The two verification paths disagree about high-S. crypto.VerifySignature, which takes 64 bytes without v, rejected the mirrored (r, n − s) signature, but crypto.Ecrecover and crypto.SigToPub recovered the right public key from it, as the EVM's ecrecover precompile does. Contracts and services that recover addresses must therefore reject high-S themselves if they treat a signature as a unique identifier.
Public keys move as 65-byte uncompressed or 33-byte compressed SEC1 points and private keys as 32-byte scalars. To see which convention a signature follows, paste it into the Ethereum signature verifier; repeated nonces across transactions of one address show up in the Ethereum nonce reuse checker.