Перейти к содержимому
ecdsa.com

P-256 или secp256k1: две 256-битные кривые, две экосистемы

На кривой NIST держатся веб, ключи доступа и защищённое оборудование, на кривой Коблица — Bitcoin, Ethereum и Nostr. Размер тот же, стойкость та же, а правила вокруг них разные.
Что сравниваетсяP-256 (secp256r1)secp256k1

Выбор между P-256 и secp256k1 редко бывает свободным: кривая обычно приходит вместе с экосистемой. Обе — 256-битные кривые Вейерштрасса простого порядка со стойкостью около 128 бит и одинаковыми размерами ключей и подписей, но они различаются происхождением, набором платформ, которые их поддерживают, и соглашениями, надстроенными поверх них, а ошибки возникают именно там, где данные переходят из одного мира в другой.

Коротко о главном

P-256 (secp256r1, prime256v1)secp256k1
Где определенаNIST SP 800-186, § 3.2.1.3; SEC 2, § 2.4.2SEC 2, § 2.4.1; SP 800-186 (приложение H.2) допускает её для блокчейнов
Уравнениеy² = x³ − 3x + b по модулю p = 2²⁵⁶ − 2²²⁴ + 2¹⁹² + 2⁹⁶ − 1y² = x³ + 7 по модулю p = 2²⁵⁶ − 2³² − 977
Происхождение параметровb получен через SHA-1 из seed, выбор которого так и не объяснилиФиксированные минимальные коэффициенты (как у кривых Коблица)
Кофактор, стойкость1, около 128 бит1, около 128 бит
Ключи и подписи32-байтный закрытый ключ, 33- или 65-байтный открытый ключ, 64-байтная подпись в формате rawТе же
OID1.2.840.10045.3.1.71.3.132.0.10
JOSE / COSEES256 / −7ES256K / −47 (RFC 8812)
Node.js 26 (OpenSSL 3.6.5), подписей / проверок в секундуоколо 68 800 / 27 200около 6 500 / 7 200
@noble/curves 2.3.0, подписей / проверок в секундуоколо 3 800 / 870около 3 800 / 1 180
WebCrypto, TLS 1.3, WebAuthnДаНет
Secure Enclave от Apple, карты PIV, большинство HSMДаРедко (AWS KMS предлагает ECC_SECG_P256K1)
Где обычно используетсяTLS-сертификаты, ключи доступа, JWT, удостоверения устройствBitcoin, Ethereum, Nostr, большинство EVM-сетей

Скорость измерялась на одном ядре Apple M4 Max.

Происхождение и доверие

Кривую P-256 NIST опубликовал в 1999 году и стандартизировал в FIPS 186-2 (2000), а SECG — под именем secp256r1. Простой модуль её поля имеет особый вид, который позволяет быстро выполнять приведение по модулю, а коэффициент b получен из seed с помощью SHA-1, как предписывала принятая тогда процедура генерации «проверяемо случайных» параметров. Откуда взялся этот seed, так и не объяснили, и после разоблачений, связанных с Dual_EC_DRBG, некоторые разработчики криптосистем перестали доверять кривым NIST. Ни одной атаки на P-256, связанной с этим seed, так и не нашли, и она остаётся самой тщательно изученной из кривых, которые применяются на практике.

secp256k1 взята из SEC 2 (2000). При a = 0 и b = 7 скрывать в параметрах нечего, а особая структура кривой даёт эффективно вычислимый эндоморфизм (метод GLV), который ускоряет умножение точки на скаляр. В 2009 году выбор Сатоси Накамото для Bitcoin пал именно на неё, что по тем временам было необычно, а затем этому примеру последовал Ethereum. NIST SP 800-186 (2023) прямо разрешает secp256k1 «для приложений, связанных с блокчейнами».

Порядок обеих кривых — простое число, поэтому тонкостей с кофактором нет, и обе одинаково уязвимы для алгоритма Шора.

Поддержка в платформах и библиотеках

Именно здесь кроется настоящее различие. P-256 встроена во всё, что управляет ключами за вас: в WebCrypto любого браузера, в TLS-стеки всех операционных систем, в Secure Enclave и CryptoKit от Apple, в Android Keystore, TPM 2.0, смарт-карты PIV и во все облачные KMS. Ключи доступа используют её по умолчанию, а Baseline Requirements CA/Browser Forum допускают её для публично доверенных сертификатов.

secp256k1 нет ни в WebCrypto, ни в TLS 1.3 (ещё RFC 8422 объявил устаревшим её идентификатор для TLS 1.2), а универсальные библиотеки поддерживают её по остаточному принципу. Поэтому программы для блокчейнов опираются на специализированные реализации: в Bitcoin Core это libsecp256k1 с постоянным временем выполнения, в других проектах — @noble/curves, k256 для Rust и go-ethereum/crypto для Go. Аппаратные кошельки её поддерживают, корпоративные HSM — по-разному, а AWS KMS предлагает её как спецификацию ключа ECC_SECG_P256K1, причём только для подписи.

Производительность

Раз размеры одинаковы, скорость зависит от качества реализации, а не от кривой. В OpenSSL для P-256 есть ассемблерный код, оптимизированный вручную, а для secp256k1 — универсальный, поэтому Node.js 26.10 (OpenSSL 3.6.5) подписывает на P-256 примерно в 10 раз быстрее: около 68 800 подписей в секунду против 6 500 на одном ядре Apple M4 Max. На чистом JavaScript картина отчасти обратная: @noble/curves 2.3.0 подписывает на обеих кривых с одинаковой скоростью, а подписи secp256k1 проверяет примерно на треть быстрее благодаря эндоморфизму. libsecp256k1 ещё быстрее. Вывод: измеряйте производительность той библиотеки, которую будете поставлять, а не кривой.

Чем различаются соглашения

Одна и та же математика ECDSA в каждом из этих миров сопровождается своими правилами.

  • Хеширование. P-256 используют вместе с SHA-256 (ES256, ecdsa-with-SHA256). Bitcoin подписывает двойной хеш SHA-256, Ethereum — хеш Keccak-256, а это не то же самое, что SHA3-256.
  • Кодировка. X.509 и TLS используют DER, JOSE и WebCrypto — raw r‖s; Ethereum дописывает байт восстановления v, так что всего получается 65 байт, а в подписанных сообщениях Bitcoin перед подписью стоит байт заголовка.
  • Восстановление открытого ключа. Ethereum никогда не передаёт открытые ключи: восстановление (ecrecover) вычисляет ключ по подписи, после чего сравнивается адрес. Протоколы на P-256 вместо этого передают ключ или заверяют его сертификатом.
  • Low-S. У каждой подписи ECDSA (r, s) есть двойник (r, n − s). Политика ретрансляции Bitcoin и правила транзакций Ethereum (EIP-2) принимают только форму low-S; обычные реализации проверки для P-256 принимают обе.
  • Schnorr. Taproot добавил в Bitcoin 64-байтные подписи Schnorr по BIP-340 с 32-байтными ключами x-only на secp256k1; их же использует Nostr. Стандартной схемы Schnorr на P-256 нет.

Пластичность легко продемонстрировать в Node.js, где поддержка secp256k1 построена на OpenSSL:

Node.js 26: на secp256k1 проверку проходят и (r, s), и (r, n − s)
import { generateKeyPairSync, sign, verify } from "node:crypto";

// Group order of secp256k1 (SEC 2 §2.4.1).
const n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;

const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "secp256k1" });
const message = Buffer.from("hello");
const raw = sign("sha256", message, { key: privateKey, dsaEncoding: "ieee-p1363" });

const r = raw.subarray(0, 32);
const s = BigInt("0x" + raw.subarray(32).toString("hex"));
const flipped = Buffer.concat([r, Buffer.from((n - s).toString(16).padStart(64, "0"), "hex")]);

const check = (sig) => verify("sha256", message, { key: publicKey, dsaEncoding: "ieee-p1363" }, sig);
console.log("(r, s) and (r, n - s) both verify:", check(raw) && check(flipped));
console.log("exactly one of them is low-S:", (s <= n / 2n) !== (n - s <= n / 2n));
Результат
(r, s) and (r, n - s) both verify: true
exactly one of them is low-S: true

OpenSSL не приводит подписи к low-S и не требует low-S при проверке, поэтому подписи, полученные таким способом, нужно нормализовать, прежде чем их примут Bitcoin или Ethereum. Инструмент проверки подписей Ethereum отмечает значения high-S.

Что когда выбирать

  • Веб, TLS, ключи доступа, JWT, ключи на мобильных и других устройствах: P-256, потому что аппаратно платформы ничего другого не предлагают.
  • Bitcoin, Ethereum и EVM-сети, Nostr: secp256k1 с правилами хеширования, кодирования, восстановления ключа и low-S, принятыми в конкретной сети.
  • Связка двух миров (например, кошелёк на смарт-контракте, которым управляют с помощью ключа доступа): пусть каждая кривая остаётся в своей области. Обновление Fusaka в Ethereum (декабрь 2025 года) добавило EIP-7951 — прекомпилированный контракт для проверки подписей P-256 по адресу 0x100 стоимостью 6 900 единиц газа, а многие роллапы предлагают совместимый прекомпилированный контракт RIP-7212, поэтому контракты могут проверять подписи ключей доступа напрямую.
  • Новый протокол со свободным выбором: ни та ни другая; для программных ключей рассмотрите Ed25519, для ключей с аппаратной защитой — P-256.

Заметки о миграции

Ключи одной кривой нельзя преобразовать в ключи другой; смена кривой означает новые ключи, а в блокчейнах — и новые адреса.

  1. Не используйте один и тот же ключевой материал на разных кривых. 32-байтный секрет — допустимый закрытый ключ на обеих кривых, но полученные из него открытые ключи никак не связаны между собой; относитесь к этому как к ловушке, а не как к полезной возможности.
  2. Перенося подписание secp256k1 в HSM или KMS, убедитесь, что такой тип ключа там есть, рассчитывайте получать подписи в DER, преобразуйте их в raw r‖s, нормализуйте к low-S и вычислите идентификатор восстановления самостоятельно, перебрав оба варианта чётности.
  3. Проверяя подписи P-256 в контракте EVM, используйте проверенную библиотеку или прекомпилированный контракт, если сеть его предоставляет; никогда не пишите модульную арифметику на Solidity вручную.
  4. В JOSE переход с ES256K на ES256 меняет alg, crv и сам ключ; на переходный период опубликуйте оба ключа с разными значениями kid.

Источники

Все сравнения