How Exactly are Signatures Generated on Avalanche

I know there’s plenty of specs that provide a topical overview of how the signature is generated on Avalanche (via the secp256k1 curve). But how exactly is the signature generated?

Like, specifically, I’m curious about how the ‘nonce’ is derived in the secp256k1 signature operation.

I can tell that its deterministic, but nothing I’ve seen ties it to RFC-6979 standard. So, if not that, what is being used to determine the ‘nonce’ (k) for each signature? My best guess (after pouring over documentation for hours) is that it must be a function of the actual message hash itself (but not via any HMAC construction).

If there are any devs that could shed some light on this, that would be amazing. Thank you!

  • Curious Wallet Developer

Great question! I’ll walk through how RFC-6979 signatures (which avoid nonce reuse) are generated in AvalancheGo (used by avalanche-cli) and AvalancheJS (used by wallet.avax.network) below.

AvalancheGo Signature Generation

1) Sign
2) SignHash

Note that we call the ecdsa package in the github.com/decred/dcrd repository directly as is recommended by their README: dcrd/README.md at 9408498fd00555dd268e4987e5c89cd53ab9051f · decred/dcrd · GitHub

3) ecdsa.SignCompact

Note that SignCompact explicitly states that the caller must provide the result of hashing a larger message (which is performed in “1) Sign”). It does not stipulate that this hash must be HMAC’d as that will be done in “5) secp256k1.NonceRFC6979”.

4) signRFC6979
5) secp256k1.NonceRFC6979
6) rawSigToSig

This utility function just reorders [v||r||s] to be [r||s||v].

AvalancheJS Signature Generation

1) sign
2) keypair.sign
3) ec.sign

The README for indutny/elliptic states that the implementation uses RFC6979 to generate deterministic “k” values (the logic used in “3) ec.sign”): elliptic/README.md at 43ac7f230069bd1575e1e4a58394a512303ba803 · indutny/elliptic · GitHub

Compliance Tests

To demonstrate that both AvalancheGo and AvalancheJS produce RFC6979-compliant signatures, we also added compliance tests to both repos using the test cases provided in this BitcoinTalk thread: Deterministic Usage of DSA and ECDSA Digital Signature Algorithms (RFC 6979).

You can find the compliance tests here:

Hope that helps with your wallet development (and anyone else who may be doing so)! Please reach out if you have any additional questions.

3 Likes

If you’d like to verify any of this yourself without running any code locally, visit the site Paul Miller — Noble cryptography (which runs a hosted version of GitHub - paulmillr/noble-secp256k1: Fastest JS implementation of secp256k1. Independently audited, high-security, 0-dependency ECDSA & Schnorr signatures., a popular and audited secp256k1 library that produces RFC6979-compliant signatures).

You can then select any one of the passing compliance tests from the AvalancheGo PR (Add rfc6979 test vectors by StephenButtolph · Pull Request #1222 · ava-labs/avalanchego · GitHub). In this case, we select the first one:

You can then put the corresponding private key and message into the website shared above (Paul Miller — Noble cryptography) and it will produce an identical signature (see the “compact” signature response): 33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262

1 Like