Go поставляет криптографию в стандартной библиотеке, а начиная с Go 1.24 основные примитивы находятся в Go Cryptographic Module, созданном для FIPS 140-3. crypto/ecdsa подписывает и проверяет, crypto/x509 читает ключи и сертификаты, а в Go 1.27.3 рядом с crypto/ed25519 появились crypto/mlkem (ML-KEM-768/1024) и crypto/mldsa (ML-DSA-44/65/87). Поддержки secp256k1 нет: код для Ethereum и Bitcoin использует пакеты go-ethereum или decred.
Всё в crypto/ecdsa работает с дайджестом, который вычислили вы: пакет никогда не хеширует данные сам. Хуже неверной подписи то, что длинные входные данные молча усекаются до размера кривой: подпись над 46-байтовыми входными данными прошла проверку для других данных с теми же первыми 32 байтами. Всегда сначала хешируйте, как это делает пример. SignASN1, VerifyASN1 и интерфейс crypto.Signer работают с ASN.1 DER; для WebCrypto, JWS и других сторон, использующих raw r‖s, нужны Sign/Verify, а целые числа нужно дополнять с помощью FillBytes: Bytes() отбрасывает ведущие нулевые байты, поэтому каждое r или s, которое начинается с нулевого байта, оказывается на один байт короче.
Подписи рандомизированы, и начиная с Go 1.26 переданный io.Reader игнорируется, если не задано GODEBUG=cryptocustomrand=1: две подписи, созданные с Reader из одних нулей, различались. Тесты, которые получали воспроизводимые подписи с фиксированным Reader, перестали работать; документированная замена — testing/cryptotest.SetGlobalRandom. Значение s не нормализуется, а VerifyASN1 принимает значения из обеих половин диапазона, поэтому для проверяющих сторон, которые строго требуют low-S, s в подписи нужно заменить на n − s.
Разбор ключей рассчитан прежде всего на DER. x509.ParsePKIXPublicKey, получив текст PEM, завершается ошибкой asn1: structure error: tags don't match, поэтому сначала вызовите pem.Decode. ecdsa.ParseUncompressedPublicKey и ecdsa.ParseRawPrivateKey читают голую точку SEC1 и скаляр; сжатые точки отклоняются, а функции чтения для PKCS#8, зашифрованного парольной фразой, нет. На некорректной подписи VerifyASN1 возвращает false и никогда не возвращает ошибку.
Чтобы сравнить подпись из Go с подписью другого стека, преобразуйте её в конвертере DER ⇄ raw и проверьте в инструменте проверки подписей; проблемы с разбором сертификатов проще всего увидеть в декодере сертификатов.