Ethereum の署名を扱う Go のサービスは、通常 github.com/ethereum/go-ethereum/crypto と accounts をインポートします。cgo を有効にすると、このパッケージは go-ethereum に同梱された libsecp256k1 のコピーを使い、CGO_ENABLED=0 では純粋な Go で書かれた decred の実装にフォールバックします。チェックでは両方のビルドを実行し、すべての事実が同じ結果になりました。
crypto.Sign(hash, key) はちょうど 32 バイトを受け取り(それ以外では hash is required to be exactly 32 bytes になります)、ハッシュの計算もプレフィックスの付加も行いません。ログインメッセージは、先に accounts.TextHash に通す必要があります。この関数は EIP-191 のプレフィックスを付けて keccak-256 でハッシュします。チェックでは、独立した keccak 実装と照合してこれを確認しました。代わりにメッセージの keccak にそのまま署名すると、ethers、viem、ウォレットの結果とは決して一致しない署名になります。
署名は 65 バイトで、リカバリ ID は v = 0 または 1 です。一方、ウォレット、ethers、viem、web3.py はここに 27 または 28 を入れます。crypto.Ecrecover は v = 27/28 を invalid signature recovery id で拒否したため、サンプルのように、受け取るときに 27 を引き、送り出すときに 27 を足してください。nonce は RFC 6979 に従い(署名は独立したリファレンス実装と一致しました)、s は常に low-S です。
2 つの検証経路は、high-S の扱いが異なります。v を含まない 64 バイトを受け取る crypto.VerifySignature は鏡像の (r, n − s) 署名を拒否しましたが、crypto.Ecrecover と crypto.SigToPub は、EVM の ecrecover プリコンパイルと同様に、その署名から正しい公開鍵を復元しました。そのため、アドレスを復元するコントラクトやサービスで署名を一意の識別子として扱う場合は、high-S を自ら拒否しなければなりません。
公開鍵は 65 バイトの非圧縮形式または 33 バイトの圧縮形式の SEC1 の点として、秘密鍵は 32 バイトのスカラーとしてやり取りされます。署名がどの規約に従っているかは、Ethereum 署名検証ツールに貼り付けると確認できます。1 つのアドレスのトランザクション間で nonce が繰り返されていれば、Ethereum nonce 再利用チェッカーで見つかります。