Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deterministic Nonce Generation for ECDSA #46

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

julmb
Copy link

@julmb julmb commented Mar 7, 2025

This adds the main algorithm from RFC 6979, which generates deterministic nonces for ECDSA signing from the private key and the message hash to be signed.

According to RFC 6979 Section 3.3, the nonce generation can be viewed as a result of generating bits using the HMAC_DRBG PRNG from NIST.SP.800-90Ar1. This architecture allows for a more clean separation between the generation of random bits and the usage of those bits for generating a nonce to be used in ECDSA. Thus, I added a new DRG instance HmacDRG in Crypto.Random.HmacDRG.

It was important to me to implement the algorithm from RFC 6979 faithfully and to make sure that the resulting nonces are exactly the same. The RFC contains 150 test cases across 15 curves, 2 messages, and 5 hash functions (see also #44). By making sure that the results are exact, they can be compared to these test cases to gain some confidence in the correctness of the algorithm.

This requirement also meant that I could not use the Crypto.Number.Generate.generateParams function to generate the nonce from a properly initialized HmacDRG, since generateParams takes the bits from the wrong end of a sequence of generated bytes. Because of this, I added the function Crypto.Number.Generate.generatePrefix.

Finally, the function Crypto.PubKey.ECC.ECDSA.deterministicNonce implements the main algorithm. The description in RFC 6979 Section 3.2 contains many technical details about shifting bits, and converting and truncating sequences. It turned out that existing functions like i2ospOf_ and dsaTruncHashDigest implemented most of the required semantics so the final implementation is a lot shorter than the version presented in the RFC.

The function deterministicNonce has the following signature:

deterministicNonce
    :: (HashAlgorithm hashDRG, HashAlgorithm hashDigest)
    => hashDRG -> PrivateKey -> Digest hashDigest -> (Integer -> Maybe a) -> a

The idea is that the parameter with type Integer -> Maybe a is one of the sign*With functions. The algorithm will continue generating nonces until the given sign*With function accepts one and then pass on the result.

@kazu-yamamoto kazu-yamamoto self-requested a review March 9, 2025 22:36
@kazu-yamamoto
Copy link
Owner

This PR conflicts the current main.
Before I start reviewing, would you resolve the conflicts?

@julmb
Copy link
Author

julmb commented Mar 10, 2025

I have rebased this onto main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants