Deterministic ECDSA Signatures
Preamble
- BIP
- 461
- Layer
- Applications
- Title
- Deterministic ECDSA Signatures
- Author
- Liam Gilligan
- Status
- Draft
- Type
- Specification
- Assigned
- 2026-08-12
- License
- CC0-1.0
- Discussion
- 2026-06-09: https://groups.google.com/g/bitcoindev/c/boEZRlqczvw
Abstract
This document specifies an ECDSA signing algorithm whose output is fully determined by the secret key and the message being signed. Its signatures are at most 70 bytes when DER encoded, rather than 72 for an arbitrary valid ECDSA signature.
Motivation
Under current consensus rules, a valid ECDSA signature of any message under any key has two degrees of freedom: the signer's free choice of nonce fixes r1, and two possible values of s follow from a specific r. A malicious signer can exploit that freedom to generate signatures that leak key material2, but a standardized, deterministic signing algorithm removes that freedom. Signers expected to comply with such an algorithm cannot leak key material without risking detection: a key holder can load the same secret key into two independent signers, sign the same message on both, and compare the results, as any difference reveals that at least one signer is not following this specification.
The standardization of the deterministic algorithm is what enables leak detection, as a nonstandard algorithm has no other implementations to cross-check against.
Definitions
- The value (n - 1) / 2 is the half curve order, where n is the order of the secp256k1 curve.
- A given signature (r, s) is considered low-r when r < 2255, and is otherwise considered high-r.
- A given signature (r, s) is considered low-s when s is less than or equal to the half curve order, and is otherwise considered high-s.
- Low-r grinding is the process of regenerating a signature with a new nonce until it is a low-r signature.
- Low-s normalization is the process of replacing a signature (r, s) with the equivalent signature (r, n - s) if (r, s) is high-s.3
Specification
Notation
The following conventions are used, with constants as defined for secp256k1.
Lowercase variables represent integers, byte arrays, or signatures:
- The constant p refers to the field size, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F.
- The constant n refers to the curve order, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.
- The constant half_order refers to the half curve order, (n - 1) / 2.
- The constant empty_bytestring refers to the byte array of length zero.
- An ECDSA signature sig can be represented literally by an integer pair (r, s), with 0 < r, s < n.
Points on the curve with equation y2 = x3 + 7 over the integers modulo p:
- The point at infinity is the identity element of the curve group, and is the only point without X and Y coordinates.
- The function is_infinite(P) returns whether or not P is the point at infinity.
- x(P) and y(P) are integers in the range 0..p-1 and refer to the X and Y coordinates of a point P (assuming it is not infinity).
- The constant G refers to the base point, for which x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 and y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8.
- Addition of points refers to the usual elliptic curve group operation.
- Multiplication (⋅) of an integer and a point refers to the repeated application of the group operation.
Functions and operations:
- || refers to byte array concatenation.
- The function int(x), where x is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is x.
- The function bytes(l, x), where x is an integer, returns the l-byte encoding of x, most significant byte first.
- The function bytes_le(l, x), where x is an integer, returns the l-byte encoding of x, least significant byte first.
- The function fill_bytes(l, x), where x is a byte, returns the length l byte array in which every byte is x.
- The function hmac(k, m), where k and m are byte arrays, returns HMAC-SHA2564 with key k over message m.
- x-1 refers to the modular multiplicative inverse of the integer x modulo n.
Algorithms
This section specifies the following algorithms:
- nonce_rfc6979(sk, msghash, extra, count) derives a nonce deterministically.
- sign(sk, msghash, extra) produces an ECDSA signature under a given additional data input.
- verify(sig, P, msghash) checks an ECDSA signature.
- DeterministicSign(sk, msghash) grinds sign until r is low and normalizes s.
Nonce Derivation
Input:
- The secret key sk: a 32-byte array
- The message hash msghash: a 32-byte array
- The additional data extra: a byte array, possibly empty
- The attempt counter count: an integer, count >= 0
The algorithm nonce_rfc6979(sk, msghash, extra, count) is defined as:5
- Let h = bytes(32, int(msghash) mod n)6
- Let V = fill_bytes(32, 0x01)
- Let K = fill_bytes(32, 0x00)
- Let K = hmac(K, V || 0x00 || sk || h || extra)
- Let V = hmac(K, V)
- Let K = hmac(K, V || 0x01 || sk || h || extra)
- Let V = hmac(K, V)
- Let V = hmac(K, V)
- For j = 1, ..., count:
- Let K = hmac(K, V || 0x00)
- Let V = hmac(K, V)
- Let V = hmac(K, V)
- Return V
ECDSA Signing
Input:
- The secret key sk: a 32-byte array
- The message hash msghash: a 32-byte array
- The additional data extra: a byte array, possibly empty
The algorithm sign(sk, msghash, extra) is defined as:
- Let d = int(sk)
- Fail if d = 0 or d >= n
- For count = 0, 1, ..., 232 - 1:7
- Let nonce = nonce_rfc6979(sk, msghash, extra, count)
- Let k = int(nonce)
- Continue if k = 0 or k >= n
- Let R = k⋅G
- Let r = x(R) mod n
- Continue if r = 0
- Let s = k-1 * (d * r + int(msghash)) mod n
- Continue if s = 0
- Return (r, s)
- Fail
ECDSA Verification
Input:
- The signature sig: (r, s)
- The public key P: a point
- The message hash msghash: a 32-byte array
The algorithm verify(sig, P, msghash) is defined as:
- If is_infinite(P):
- Return false
- If y(P)2 ≠ x(P)3 + 7 mod p:
- Return false
- Let (r, s) = sig
- If r <= 0 or r >= n:
- Return false
- If s <= 0 or s >= n:
- Return false
- Let w = s-1
- Let u1 = w * int(msghash) mod n
- Let u2 = w * r mod n
- Let R = u1⋅G + u2⋅P
- If is_infinite(R):
- Return false
- If x(R) mod n ≠ r:
- Return false
- Return true
Deterministic Signing
Input:
- The secret key sk: a 32-byte array
- The message hash msghash: a 32-byte array
The algorithm DeterministicSign(sk, msghash) is defined as follows. The grind counter is 0 for the initial call to sign, which supplies no additional data, and takes the value of the loop variable i for every subsequent call.
- Fail if int(sk) = 0 or int(sk) >= n
- Let (r, s) = sign(sk, msghash, empty_bytestring)8
- Let i = 1
- While r >= 2255:9
- If i >= 232:
- Fail
- Let extra = bytes_le(4, i) || fill_bytes(28, 0x00)10
- Let (r, s) = sign(sk, msghash, extra)
- Let i = i + 1
- If i >= 232:
- If s > half_order:11
- Let s = n - s
- Let P = int(sk)⋅G
- If verify((r, s), P, msghash) returns false, abort12
- Return (r, s)
The predicate r >= 2255 is equivalent to testing that the most significant byte of bytes(32, r) is greater than or equal to 0x80.
Rationale
Bitcoin encodes ECDSA signatures in a strict DER form with an additional 1-byte sighash flag, which serializes r and s as arbitrary-length big-endian signed integers13. Their encoding being signed means that even though every value of r and s can be encoded in 32 bytes or less as an unsigned integer, a null byte must be prepended if the most significant bit is set, raising the maximum size to 33 bytes each. The maximum size of a DER encoded ECDSA signature is 72 bytes, or 73 with the sighash flag.
The signing algorithm as specified makes use of low-r grinding and low-s normalization14 to exclusively produce low-r and low-s signatures. This produces signatures with a maximum DER encoding size of 70 bytes, or 71 with the sighash flag.15 Against a signer that normalizes s but does not grind, low-r grinding saves on average 0.5 vbytes per signature in legacy inputs and 0.125 vbytes in v0 segwit inputs.16 In 2-of-3 P2SH inputs it saves 2.5 vbytes on average, as a single high-r signature pushes the input script's length indicator from one byte to three. The cost is rather cheap: low-r grinding requires an additional signing operation and low-s normalization requires a scalar subtraction. Uniform adoption is worthwhile independently of the savings, as a signer that does not grind is identifiable on-chain by its high-r signatures.17
Low-r Grinding
Why RFC 6979
Grinding requires a nonce derivation that is deterministic in the secret key and message, and that additionally accepts a counter, so that a fresh and unrelated nonce can be derived for the same key and message.18 RFC 6979 provides exactly this: it is the IETF's standard deterministic nonce derivation for ECDSA, and its section 3.6 admits an additional data input, for which it names a signature counter as an example:19
It suffices that the additional data k' is non-repeating (e.g., a signature counter or a monotonic clock) to ensure "random-looking" signatures are indistinguishable, in a cryptographic way, from plain (EC)DSA signatures.
Potential Alternate Grinding Methods
A fresh random nonce on each attempt. Drawing each candidate nonce from a cryptographically secure random source also yields unrelated nonces, and is a valid means of producing low-r signatures. Such a method is not adopted because the resulting signatures are not reproducible, which reopens the exfiltration problem described in the Motivation. Randomness would buy some protection against fault injection, which is why BIP 340 recommends it for Schnorr signatures. Deterministic derivation is nonetheless established practice for ECDSA in Bitcoin, as RFC 6979 is libsecp256k1's default nonce function and Bitcoin Core requests it explicitly.20
Grinding for smaller r. In order for a lower r value to save any space, it must be an entire byte smaller, and thus must have the leading 9 bits unset rather than just the leading bit. Computing such an r value would take 512 signing operations on average, as opposed to the two of regular low-r grinding.21 Grinding for a smaller r was deemed too expensive to be adopted widely. Because few signers would do so, the signers that did would be identifiable on-chain.22
Speeding up grinding with the λ endomorphism. It was suggested to use secp256k1's λ endomorphism to quickly compute alternative nonces.23 Low-r grinding as specified takes only two point multiplications on average. The added complexity of using the λ endomorphism cannot meaningfully improve on that.24
Backward Compatibility
Signatures generated under this specification are normal valid signatures and will verify under existing consensus rules, and thus are fully backward compatible.
Copyright
This BIP is licensed under the CC0-1.0 license.
Technically a signer selects a nonce k, from which r = x(k⋅G) mod n follows. It cannot target a particular r without solving the discrete logarithm problem, and only about half the integers modulo n occur as an r at all, since r must be the x-coordinate of a curve point. What the signer has is free choice of k, and so free choice among the r values that result.↩︎
Dark Skippy is a method by which malicious signing device firmware embeds seed material in the nonces of otherwise valid signatures, from which an attacker who observes those signatures on-chain can recover the seed. Raised in the context of this document by Craig Raw; see this comment.↩︎
Low-s normalization preserves signature validity: Let (r, s) be a high-s signature that verify accepts for a public key P and message hash msghash. Let (r, s') be a low-s signature with s' = n - s, and let us consider whether verify will accept it under P and msghash. The checks on P, msghash, and r do not involve s and are unchanged, and s' passes the range check because 0 < s < n implies 0 < n - s < n. Since s' ≡ -s (mod n), w' = -w, so u1' = -u1, u2' = -u2, and consequently R' = -R. The x-coordinate of a finite point is invariant under negation, so x(R') mod n = r, and thus verify accepts (r, n - s) and low-s normalization preserves validity.↩︎
RFC 2104: HMAC: Keyed-Hashing for Message Authentication, instantiated with SHA-256 as specified in FIPS 180-4.↩︎
K and V are the internal state variables of the HMAC-based generator specified in RFC 6979 section 3.2, and carry its names. Both are 32-byte arrays rather than curve points, and K is unrelated to the nonce k.↩︎
This reduction is RFC 6979's bits2octets(h1), required by section 3.2d. It has no effect unless int(msghash) >= n, which occurs with probability about 1.27 · 2-128. libsecp256k1 performs it as
msgmod32innonce_function_rfc6979; see libsecp256k1src/secp256k1.c. Bitcoin Core acquired the reduction in v24.0, having fed the unreduced hash from v0.17.0 through v23.0.↩︎count advances the RFC 6979 generator without changing extra, and is distinct from the grind counter i. libsecp256k1 increments the same counter whenever the derived nonce falls outside [1, n-1], or the resulting r or s is zero; see
secp256k1_ecdsa_sign_innerin libsecp256k1src/secp256k1.c, which retries in both cases rather than failing. Each of those conditions has probability on the order of 2-128 or less, so count is 0 for every signature produced in practice. Because sign rejects an out-of-range secret key, and DeterministicSign rejects one before the loop is entered, no secret key makes every attempt fail, so the loop's Fail branch is unreachable in practice. An implementation may therefore omit the retry and fail on the first unusable nonce instead. Retrying is recommended and costs nothing, and neither choice affects the test vectors or interoperability.↩︎Omitting the additional data makes RFC 6979 hash a 64-byte seed rather than a 96-byte one, so grind counter 0 does not produce the nonce that 32 null bytes would. See libsecp256k1
src/secp256k1.c,nonce_function_rfc6979, which notes that the argument mixtures have distinct lengths and so cannot emulate one another.↩︎For an event of probability q, the expected number of attempts before the first success is 1/q. A low r arises with probability approximately 1/2, so grinding as specified takes two attempts on average, needs more than j attempts with probability 2-j, and terminates with probability 1; Bitcoin Core allots a 32-bit counter, which cannot be exhausted in practice. Grinding for an r a whole byte smaller instead has q = 2-9, giving 512 attempts on average. That threshold is nine bits rather than eight because DER restores the padding byte whenever the leading content byte has its most significant bit set, so r must fall below 2247 rather than 2248.↩︎
The little-endian counter is an artifact of
CKey::Signwriting the counter into a 32-byte entropy buffer withWriteLE32; see Bitcoin Coresrc/key.cpp.↩︎libsecp256k1
src/ecdsa_impl.h,secp256k1_ecdsa_sig_sign:high = secp256k1_scalar_is_high(sigs); secp256k1_scalar_cond_negate(sigs, high);↩︎Verifying the signature before leaving the signer prevents random or attacker provoked computation errors. This prevents publishing invalid signatures which may leak information about the secret key. It is recommended, but can be omitted if the computation cost is prohibitive, at the cost of detecting faults in the signing computation. The preceding wording is taken from the equivalent step in the signing algorithm of BIP 340, which is licensed under BSD-2-Clause. Bitcoin Core performs the check unconditionally in
CKey::Sign. Because the check cannot alter the returned signature, omitting it affects neither the test vectors nor interoperability.↩︎Note that transactions with high-s signatures are valid but currently will not be relayed based on standard policy: see Bitcoin Core
src/policy/policy.h.↩︎A signer that normalizes s but does not grind falls between the two bounds, at 71 bytes of DER. BIP 62, "DER encoding", gives that case as "the total signature size being at most 72 bytes (and on average 71.494 bytes)", counting the sighash flag. The average falls slightly below 71.5 because r occasionally encodes in fewer than 32 bytes.↩︎
See, e.g., this comment and the surrounding discussion in the pull request that introduced grinding to Bitcoin Core.↩︎
Two published signatures whose nonces stand in a relation an attacker can find will leak the secret key. Neither the intermediate attempts of a grind nor the counter that produced the successful one is published, so the constraint binds across messages rather than within a single grind loop; RFC 6979 satisfies it in both directions in any case. A fresh nonce from a cryptographically secure random source on each attempt also satisfies it, though the resulting signatures are not reproducible.↩︎
RFC 6979: Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA). The additional data input and the non-repetition requirement are given in section 3.6.↩︎
secp256k1_nonce_function_defaultisnonce_function_rfc6979; see libsecp256k1src/secp256k1.c. Bitcoin Core passessecp256k1_nonce_function_rfc6979tosecp256k1_ecdsa_signinCKey::Sign.↩︎For an event of probability q, the expected number of attempts before the first success is 1/q. A low r arises with probability approximately 1/2, so grinding as specified takes two attempts on average, needs more than j attempts with probability 2-j, and terminates with probability 1; Bitcoin Core allots a 32-bit counter, which cannot be exhausted in practice. Grinding for an r a whole byte smaller instead has q = 2-9, giving 512 attempts on average. That threshold is nine bits rather than eight because DER restores the padding byte whenever the leading content byte has its most significant bit set, so r must fall below 2247 rather than 2248.↩︎
Bitcoin Core PR #13666, "Always create signatures with Low R values", released in Bitcoin Core v0.17.0. The review discussion also considered grinding for even smaller r values; see this comment.↩︎
Suggested during review of the pull request that introduced grinding to Bitcoin Core; the replies that follow discuss the nonce distribution it would produce.↩︎
A single point multiplication for the nonce k also yields the r values belonging to λk and λ2k, where λ is a primitive cube root of unity modulo the group order; see libsecp256k1
src/scalar_impl.h,secp256k1_const_lambda. Since a signer must compute one point multiplication in any case, this saves at most one per signature, and capturing it requires curve arithmetic outside the signing routine.↩︎