Skip to content

crypto: support deterministic ECDSA/DSA signatures#62252

Draft
panva wants to merge 2 commits intonodejs:mainfrom
panva:dsa-deterministic
Draft

crypto: support deterministic ECDSA/DSA signatures#62252
panva wants to merge 2 commits intonodejs:mainfrom
panva:dsa-deterministic

Conversation

@panva
Copy link
Member

@panva panva commented Mar 14, 2026

Add dsaNonceType option to sign/verify node:crypto APIs. When set to 'deterministic', uses deterministic digital signature generation procedure per RFC 6979.

Add dsaNonceType option to sign/verify node:crypto
APIs. When set to 'deterministic', uses
deterministic digital signature generation
procedure per RFC 6979.
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/crypto
  • @nodejs/security-wg

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Mar 14, 2026
@panva
Copy link
Member Author

panva commented Mar 14, 2026

Leaving this at draft PR unless there's user interest.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 14, 2026

cc @paulmillr you might be interested / have an opinion on this

@paulmillr
Copy link

  • Random nonces are absolute garbage. break csprng and you're leaking private keys through signatures
  • Deterministic nonces are better as default, but suboptimal in some (albeit rare) situations
  • Deterministic + random combination is ideal

See RFC6979 3.6 and https://paulmillr.com/posts/deterministic-signatures/.

The suggestion is to switch to deterministic by default + add an ability to pass either specific randomness Buffer, or make node auto-generate random buffer:

  1. (default) sign() - always deterministic
  2. (option) sign(randomness: Buffer) - specific buffer of randomness; but still deterministic
  3. (option) sign(randomness: true) - auto-produce randomness; but still deterministic

@ChALkeR
Copy link
Member

ChALkeR commented Mar 14, 2026

@panva

  1. Does random here imply csprng -> nonce or (csprng, input) -> deterministic RFC 6979 -> nonce?
  2. It should be noted that any bug or change in the deterministic algo would mean an immediate leak of private keys

@panva
Copy link
Member Author

panva commented Mar 14, 2026

https://docs.openssl.org/master/man7/provider-signature/#signature-parameters > OSSL_SIGNATURE_PARAM_NONCE_TYPE

that's what this is, exposed as an opt-in option, not a new default

IIUC there are no other options available to us

@panva panva added crypto Issues and PRs related to the crypto subsystem. semver-minor PRs that contain new features and should be released in the next minor version. labels Mar 14, 2026
@ChALkeR
Copy link
Member

ChALkeR commented Mar 14, 2026

The question is about how "random nonces" work, not about how deterministic one works
There is a fundamental difference between just using csprng output as a nonce and using that as a mixin to RFC 6979 algo to get a nonce
Ok i'll check openssl

Upd:
The OpenSSL doc states:

The default value for "nonce-type" is 0 and results in a random value being used for the nonce k as defined in FIPS 186-4 Section 6.3 "Secret Number Generation".

This is... bad.
Not the fault of this PR, the current state of things is bad.

@panva
Copy link
Member Author

panva commented Mar 14, 2026

0 / random = current behaviour, csprng -> k, not changed by this PR
1 / deterministic = this PR opt-in, RFC 6979, possible future semver major default (problematic to roll out because of OpenSSL version not being a given)

noisy / hedged is not an option in OpenSSL, draft-irtf-cfrg-det-sigs-with-noise would need to be finished and published as RFC first for OpenSSL to consider it.

@panva
Copy link
Member Author

panva commented Mar 16, 2026

@ChALkeR @paulmillr @nodejs/crypto is there interest in pursuing this PR further?

@paulmillr
Copy link

V26 is around the corner, right? Could the default deterministic version be included there?

@panva
Copy link
Member Author

panva commented Mar 16, 2026

We should introduce the option to have it first and then figure out a way to change a default. Doing so for 26 isn't realistic.

OpenSSL version isn't a given, OpenSSL itself isn't a given, embedders of Node.js like electron use BoringSSL, so do Node.js-compat modes in Bun and workerd. We'll have to figure all that out.

So my question is, is having the option to as per this PR an improvement worth pursuing, knowing that it is a stepping stone to possibly having it a default in the future.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 16, 2026

  1. Does boring support it?
  2. Ideally, we should eventually switch to hedged, which are non-deterministic random-looking
    To consumers, this will look like random -> deterministic -> random switch...
    I wonder how can we avoid that

Also, once hedged are supported, users likely should not have an option to use CSPRG -> k anymore, random should be effectively an alias to hedged then.

@panva
Copy link
Member Author

panva commented Mar 16, 2026

Does boring support it?

Good question. Possibly, it may even be its very default. I would have to check.

Hedged

Yes, if Hedged/Noisy would eventually be supported in OpenSSL I would make that the default over current random with no hesitation since it's not observable.

But is that draft even going to progress? In the meantime, is "deterministic" option useful?

@paulmillr
Copy link

bitcoin-core maintainers consider openssl bad and switched away a long time ago. Other consumers seems to be fine with randomness (they don't know it's fragile). If they don't know about fragility, they aren't likely to enable the flag manually. ed25519 and ed448 are already deterministic.

So, mostly p256, p384, p521 curve users. It's useful but not too useful.

Boringssl code doesn't seem to mention RFC6979 anywhere.

@panva
Copy link
Member Author

panva commented Mar 16, 2026

Oh how fun, OpenSSL default random / 0 appears to be hedged already (despite their own docs), just not using the constructs from draft-irtf-cfrg-det-sigs-with-noise exactly.

BN_generate_dsa_nonce > ossl_bn_gen_dsa_nonce_fixed_top

/*
 * ossl_bn_gen_dsa_nonce_fixed_top generates a random number 0 <= out < range.
 * Unlike BN_rand_range, it also includes the contents of |priv| and |message|
 * in the generation so that an RNG failure isn't fatal as long as |priv|
 * remains secret. This is intended for use in DSA and ECDSA where an RNG
 * weakness leads directly to private key exposure unless this function is
 * used.
 */

https://github.com/openssl/openssl/blob/67b5686b4419b4cb8caa502711c41815f5279751/crypto/bn/bn_rand.c#L285-L395

@paulmillr
Copy link

Great news. Then the PR is worth it.

@panva
Copy link
Member Author

panva commented Mar 16, 2026

Is it? Because all it would do is introduce a "deterministic" option on top of what we know is a better default that's already in place.

@paulmillr
Copy link

Yes. Deterministic option is still useful for those who want to align to specific test vectors / implementations. It's good.

@panva
Copy link
Member Author

panva commented Mar 16, 2026

now, the docs are clear this new dsaNonceType option is for DSA/ECDSA but if eventually there's a hedged option for EdDSA for OpenSSL and we'd include it the language would need massaging because the default would be different for (EC)DSA (hedged) vs Ed25519/448 (currently deterministic)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crypto Issues and PRs related to the crypto subsystem. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. semver-minor PRs that contain new features and should be released in the next minor version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants