BouncyCastle.Cryptography (пакет, пришедший на смену Portable.BouncyCastle) — полностью управляемый код: его результаты не зависят ни от Windows CNG, ни от версии OpenSSL в Linux, и именно этим он полезен рядом с System.Security.Cryptography. Он предлагает API SignerUtilities, в котором алгоритмы задаются строками, и низкоуровневые классы, например ECDsaSigner.
Параметры ECDSA по умолчанию следуют традиции OpenSSL, а не .NET: SHA-256withECDSA выдаёт DER, а SHA-256withPLAIN-ECDSA — 64-байтовую подпись raw r‖s, которую используют собственный класс ECDsa в .NET и JWS. Путаница между ними — типичный сбой совместимости, когда обе библиотеки работают в одном приложении, причём любые некорректные входные данные приводят к возврату false, а не к исключению. Через SignerUtilities nonce выбираются случайно; ECDsaSigner с HMacDsaKCalculator воспроизвёл тестовый вектор RFC 6979. s не нормализуется, а проверка принимает high-S.
Bouncy Castle подключают ради широты поддержки: кривые от P-224 до P-521, secp256k1 и Brainpool r1; Ed25519 и Ed448, как в примере; а также ML-KEM, ML-DSA и SLH-DSA через MLKemEncapsulator, MLDsaSigner и SlhDsaSigner — и всё это работало на том же образе Linux, где библиотека базовых классов не сообщила вообще ни о какой поддержке постквантовых алгоритмов. Попробуйте эти алгоритмы в песочнице постквантовых подписей.
PemWriter записывает закрытые ключи EC в формате SEC1 -----BEGIN EC PRIVATE KEY-----, а PemReader возвращает их как AsymmetricCipherKeyPair; PKCS#8 обрабатывается через PrivateKeyInfoFactory. Версия самой сборки в строгом имени — 2.0.0 для каждого релиза 2.x, поэтому при сравнении поведения сверяйте версию пакета (здесь 2.7.0).