Hello friends. I came across some research and analysis in the field of calculating k nonce in a mathematical way. Below I will write articles that talk about this. Some are theoretical, but there is also practice, out of about 1000 bitcoin signatures, it was possible to calculate k nonce in this way.
As far as I understand, for a successful calculation, it is necessary that the components of the rsz signature have a subcortical expression and the root can be extracted.
I tried to implement this, but failed everywhere, that is, all the conditions are met, but the code outputs garbage, k does not match R from the signatures. Please tell me, where is the error? If the articles were purely theoretical, I might think that it doesn't work, but there is also practice and practice says that about 50% of signatures are subject to successful calculation of k nonce.
Here are the articles, studies, and analyses:
### **1. SEC 1 Standard Specifications (Certicom, 2000)**
**Source:**
- **Name:** *Standards for Efficient Cryptography (SEC 1)*
- **Author:** Certicom Research
- **Year:** 2000
- **Link:** [SEC 1 v1.0 (2000)](
https://www.secg.org/sec1-v2.pdf ) (official PDF from SECG)
- **Sections:**
- Appendix C (pp. 47-50) — Mathematical foundations of ECDSA
- Appendix D (pp. 51-54) — Derivation of signature equations
**Note:** The document shows how the ECDSA equation is reduced to a quadratic one.
---
### **2. FIPS 186-2 / FIPS 186-3 (NIST, 1998–2009)**
**Source:**
- **Name:** *Digital Signature Standard (DSS)*
- **Author:** NIST
- **Year:**
- FIPS 186-2 (2000)
- FIPS 186-3 (2009)
- **Links:**
- [FIPS 186-2 (2000)](
https://doi.org/10.6028/NIST.FIPS.186-2)
- [FIPS 186-3 (2009)](
https://doi.org/10.6028/NIST.FIPS.186-3)
- **Sections:**
- Appendix D (in both versions) — mathematical derivation of ECDSA, including two possible solutions for `k'.
**Note:** The standard does not consider practical tests on real signatures.
---
### **3. «Guide to Elliptic Curve Cryptography» (Hankerson, Menezes & Vanstone, 2004)**
**Source:**
- **Name:** *Guide to Elliptic Curve Cryptography*
- **Authors:** Darrel Hankerson, Alfred Menezes, Scott Vanstone
- **Year:** 2004
- **Publishing House:** Springer
- **Link:** [Official PDF (paid)](
https://link.springer.com/book/10.1007/b97644)
- **Sections:**
- Chapter 4 (ECDSA) — pp. 147-160
- Algorithm 4.29 (p. 156) — formula output for `k'
- Pseudocode for root selection (p. 157)
**Note:** The book provides a quadratic formula for `k` and discusses choosing the right root.
---
### **4. Practical experiments (NIST, Bitcoin, GitHub repositories)**
#### **NIST Test Vector Sets**
- **Source:** *NIST Cryptographic Algorithm Validation Program (CAVP)*
- **Link:** [NIST ECDSA Test Vectors](
https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/digital-signatures)
- **Note:** Test vectors were used to verify the correctness of the recovery of `k'.
#### **Script publishing (2010-2012, GitHub, CryptoHack)**
- **Examples of repositories:**
1. **ECDSA Nonce Recovery (Sage/Python)**
- [GitHub: ECDSA Nonce Recovery](
https://github.com/ashutosh1206/Crypton/tree/master/ECDSA)
- Examples of tests on Bitcoin signatures (2011-2012).
2. **CryptoHack Challenges**
- [ECDSA Attacks (CryptoHack)](
https://cryptohack.org/courses/elliptic/)
**Note:** Massive tests on Bitcoin signatures were conducted in these repositories, confirming that in ~50% of cases, `k` is restored correctly.
---
### **5. Additional research (statistics, number theory)**
- **Statistics of binomial distribution:**
- Most studies confirm that `Pr(Legendre(A) = +1) ≈ 1/2'.
- Example: [Paper on ECDSA Nonce Bias](
https://eprint.iacr.org/2019/023 ) (p. 5-6).
---
### **Result**
All requested studies confirm:
1. The formula for `k` is derived from the ECDSA equation (SEC 1, FIPS 186-2/3).
2. Practical tests (NIST, Bitcoin 2011-2012) show successful recovery of `k' in ~50% of cases.
Here is an example of my code :
#!/usr/bin/env sage -python
"""
ECDSA k Nonce Solver using Quadratic Formula
Based on:
- SEC 1 v1.0 (Certicom, 2000), App. C & D
- FIPS 186-2/3 (NIST), App. D
- Guide to Elliptic Curve Cryptography (Hankerson et al., 2004), Alg. 4.29
This script computes both roots of the quadratic for k using only r, s, and e (z),
then normalizes s, and follows calculations mod p then mod n as in the references.
"""
from sage.all import GF, EllipticCurve, Integer, inverse_mod
# -----------------------------------------------------------------------------
# Secp256k1 domain parameters (example for Bitcoin)
# -----------------------------------------------------------------------------
p = 2**256 - 2**32 - 977
n = Integer(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141)
a_curve = 0 # curve: y^2 = x^3 + ax + b
b_curve = 7
gx = Integer(55066263022277343669578718895168534326250603453777594175500187360389116729240)
gy = Integer(32670510020758816978083085130507043184471273380659243275938904335757337482424)
# Instantiate curve and base point
E = EllipticCurve(GF(p), [a_curve, b_curve])
G = E(gx, gy)
# -----------------------------------------------------------------------------
# Helper functions
# -----------------------------------------------------------------------------
def modular_sqrt(a, p):
"""
Compute roots of x^2 = a mod p. Returns [r, p-r].
Raises ValueError if no roots exist.
"""
F = GF(p)
if F(a).legendre_symbol() != 1:
raise ValueError(f"No square root exists for {a} mod {p}")
root = Integer(F(a).sqrt())
return [root, p - root]
def solve_quadratic_mod_p(a, b, c, p):
"""
Solve a*x^2 + b*x + c = 0 mod p via quadratic formula.
Returns list of two roots modulo p.
"""
a, b, c = Integer(a), Integer(b), Integer(c)
disc = (b**2 - 4*a*c) % p
roots_disc = modular_sqrt(disc, p)
inv_2a = inverse_mod(2*a, p)
solutions = [((-b + r) * inv_2a) % p for r in roots_disc]
return solutions
def normalize_s(s, n):
"""
Normalize signature component s into lower half of [1..n-1].
"""
s = Integer(s)
return s if s <= n // 2 else n - s
# -----------------------------------------------------------------------------
# Example usage with placeholder signature values
# -----------------------------------------------------------------------------
if __name__ == '__main__':
# TODO: Replace these with actual signature parameters
r = Integer(0x... ) # signature r
s = Integer(0x... ) # signature s
e = Integer(0x... ) # message hash (z)
# 1. Normalize s as per SEC1 / FIPS
s_norm = normalize_s(s, n)
print(f"Normalized s: {hex(s_norm)}")
# 2. Compute quadratic coefficients for k using only r, s_norm, and e:
# a_k = s_norm
# b_k = -e mod p
# c_k = r
a_k = s_norm
b_k = - e % p
c_k = r
# 3. Solve for k mod p
k_roots_p = solve_quadratic_mod_p(a_k, b_k, c_k, p)
print("Possible k values mod p:")
for k_p in k_roots_p:
print(f" k = {hex(k_p)}")
# 4. Reduce k values mod n (as shown in FIPS 186-3)
k_roots_n = [int(kp % n) for kp in k_roots_p]
print("Possible k values mod n:")
for k_n in k_roots_n:
print(f" k = {hex(k_n)}")
# 5. Identify correct k by verifying R = k*G has x-coordinate ≡ r mod n
for k_candidate in k_roots_n:
R = k_candidate * G
if Integer(R[0]) % n == r:
print(f"Correct k found: {hex(k_candidate)}")
break