Next scheduled rescrape ... never
01/07/2025, 03:41:22 UTC POST DELETED
Original archived How Does Nonce Bias Really Leak in ECDSA? If You Found It — Please Share Code or
Scraped on 24/06/2025, 03:41:30 UTC
How Does Nonce Bias Really Leak in ECDSA? If You Found It — Please Share Code or Insights!

Hi everyone,

I'm currently learning about ECDSA nonce bias attacks, and I’d love help understanding how even small weaknesses (1–4 bit biases) in the nonce k can leak private key information. I've seen claims of private key recovery using as little as 1-bit bias — but never seen full working code or data.

🔍 What I’m Trying to Understand:
How does a biased bit in k show up in the signature values (r, s, z)?

Can you detect this leakage just by looking at bit-level patterns in multiple signatures?

How many biased bits + how many signatures = enough to break d?

🧪 My Analysis Method (With Code Below)
Here’s how I currently try to analyze for bias:

Collect multiple valid ECDSA signatures → extract r, s, z per sig.

Convert each value to 256-bit binary.

Count how often each bit is 1 across all samples.
 ✅Code  reference?
✅ Can you share Code & data or results?
Report any bit position with strong deviation from randomness (ideal = 0.5 probability of 1).

Code:
import hashlib
from ecdsa import SigningKey, SECP256k1
from statistics import mean
from math import sqrt

curve = SECP256k1
n = curve.order

# -- ECDSA Sign with fixed nonce (for research/testing only!) --
def sign(privkey_int, nonce_int, message_bytes):
    G = curve.generator
    d = privkey_int
    k = nonce_int

    # Hash the message
    h = hashlib.sha256(message_bytes).digest()
    z = int.from_bytes(h, byteorder='big') % n  # ensure z < n

    # Calculate R = k*G
    R = k * G
    r = R.x() % n
    if r == 0:
        raise ValueError("Invalid r = 0")

    # s = k⁻¹ (z + r*d) mod n
    k_inv = pow(k, -1, n)
    s = (k_inv * (z + r * d)) % n
    if s == 0:
        raise ValueError("Invalid s = 0")

    return r, s, z

# -- Bit-level bias analysis on z --
def analyze_z_bias(z_list, bit_length=256):
    print("[+] Bit-Level Bias in Z (MSB first):")
    for bit in reversed(range(bit_length)):
        ones = sum((z >> bit) & 1 for z in z_list)
        ratio = ones / len(z_list)
        line = f"Bit {bit:3d}: 1s = {ratio:.3f}"
        if ratio in (0.0, 1.0) or abs(ratio - 0.5) > 0.05:
            line += " <-- biased"
        print(line)

# -- Correlation calculation --
def pearson_corr(x_vals, y_vals):
    xm = mean(x_vals)
    ym = mean(y_vals)
    num = sum((x - xm) * (y - ym) for x, y in zip(x_vals, y_vals))
    den = sqrt(sum((x - xm)**2 for x in x_vals) * sum((y - ym)**2 for y in y_vals))
    return num / den if den else 0.0

# -- Demo: Generate signatures and analyze bias --
def run_demo():
    privkey = 0xdeadbeef123456789abcdef0feedfacecafebabe123456789abcdef0123456789
    r_list = []
    s_list = []
    z_list = []

    for i in range(1000):
        msg = f"message {i}".encode()
        nonce = i + 1  # use incrementing nonces (DANGEROUS in real use!)
        try:
            r, s, z = sign(privkey, nonce, msg)
            r_list.append(r)
            s_list.append(s)
            z_list.append(z)
        except Exception as e:
            print(f"Skipping failed signature at i={i}: {e}")

    analyze_z_bias(z_list)

    print("\n[+] Correlation Analysis:")
    print(f"Corr(R,Z): {pearson_corr(r_list, z_list):.4f}")
    print(f"Corr(S,Z): {pearson_corr(s_list, z_list):.4f}")

# Run everything
if __name__ == "__main__":
    run_demo()
#output
python bias.py
  • Bit-Level Bias in Z (MSB first):
Bit 255: 1s = 0.519
Bit 254: 1s = 0.514
Bit 253: 1s = 0.519
Bit 252: 1s = 0.488
Bit 251: 1s = 0.510
Bit 250: 1s = 0.506
Bit 249: 1s = 0.485
Bit 248: 1s = 0.515
Bit 247: 1s = 0.487
Bit 246: 1s = 0.490
Bit 245: 1s = 0.494
Bit 244: 1s = 0.512
Bit 243: 1s = 0.505
Bit 242: 1s = 0.479
Bit 241: 1s = 0.515
Bit 240: 1s = 0.512
Bit 239: 1s = 0.521
Bit 238: 1s = 0.518
Bit 237: 1s = 0.499
Bit 236: 1s = 0.513
Bit 235: 1s = 0.520
Bit 234: 1s = 0.511
Bit 233: 1s = 0.504
Bit 232: 1s = 0.495
Bit 231: 1s = 0.476
Bit 230: 1s = 0.544
Bit 229: 1s = 0.499
Bit 228: 1s = 0.503
Bit 227: 1s = 0.491
Bit 226: 1s = 0.510
Bit 225: 1s = 0.524
Bit 224: 1s = 0.479
Bit 223: 1s = 0.502
Bit 222: 1s = 0.509
Bit 221: 1s = 0.523
Bit 220: 1s = 0.510
Bit 219: 1s = 0.526
Bit 218: 1s = 0.508
Bit 217: 1s = 0.490
Bit 216: 1s = 0.514
Bit 215: 1s = 0.514
Bit 214: 1s = 0.491
Bit 213: 1s = 0.501
Bit 212: 1s = 0.490
Bit 211: 1s = 0.502
Bit 210: 1s = 0.501
Bit 209: 1s = 0.509
Bit 208: 1s = 0.509
Bit 207: 1s = 0.500
Bit 206: 1s = 0.495
Bit 205: 1s = 0.510
Bit 204: 1s = 0.495
Bit 203: 1s = 0.498
Bit 202: 1s = 0.490
Bit 201: 1s = 0.501
Bit 200: 1s = 0.510
Bit 199: 1s = 0.484
Bit 198: 1s = 0.498
Bit 197: 1s = 0.533
Bit 196: 1s = 0.494
Bit 195: 1s = 0.518
Bit 194: 1s = 0.508
Bit 193: 1s = 0.528
Bit 192: 1s = 0.494
Bit 191: 1s = 0.492
Bit 190: 1s = 0.468
Bit 189: 1s = 0.478
Bit 188: 1s = 0.517
Bit 187: 1s = 0.519
Bit 186: 1s = 0.519
Bit 185: 1s = 0.475
Bit 184: 1s = 0.522
Bit 183: 1s = 0.500
Bit 182: 1s = 0.531
Bit 181: 1s = 0.522
Bit 180: 1s = 0.470
Bit 179: 1s = 0.506
Bit 178: 1s = 0.500
Bit 177: 1s = 0.511
Bit 176: 1s = 0.512
Bit 175: 1s = 0.491
Bit 174: 1s = 0.497
Bit 173: 1s = 0.477
Bit 172: 1s = 0.486
Bit 171: 1s = 0.516
Bit 170: 1s = 0.492
Bit 169: 1s = 0.474
Bit 168: 1s = 0.501
Bit 167: 1s = 0.475
Bit 166: 1s = 0.513
Bit 165: 1s = 0.469
Bit 164: 1s = 0.522
Bit 163: 1s = 0.515
Bit 162: 1s = 0.486
Bit 161: 1s = 0.486
Bit 160: 1s = 0.518
Bit 159: 1s = 0.479
Bit 158: 1s = 0.522
Bit 157: 1s = 0.476
Bit 156: 1s = 0.511
Bit 155: 1s = 0.505
Bit 154: 1s = 0.500
Bit 153: 1s = 0.512
Bit 152: 1s = 0.502
Bit 151: 1s = 0.497
Bit 150: 1s = 0.495
Bit 149: 1s = 0.503
Bit 148: 1s = 0.476
Bit 147: 1s = 0.481
Bit 146: 1s = 0.495
Bit 145: 1s = 0.501
Bit 144: 1s = 0.526
Bit 143: 1s = 0.474
Bit 142: 1s = 0.476
Bit 141: 1s = 0.507
Bit 140: 1s = 0.486
Bit 139: 1s = 0.529
Bit 138: 1s = 0.512
Bit 137: 1s = 0.495
Bit 136: 1s = 0.472
Bit 135: 1s = 0.508
Bit 134: 1s = 0.506
Bit 133: 1s = 0.473
Bit 132: 1s = 0.467
Bit 131: 1s = 0.498
Bit 130: 1s = 0.508
Bit 129: 1s = 0.482
Bit 128: 1s = 0.471
Bit 127: 1s = 0.511
Bit 126: 1s = 0.508
Bit 125: 1s = 0.497
Bit 124: 1s = 0.532
Bit 123: 1s = 0.488
Bit 122: 1s = 0.509
Bit 121: 1s = 0.516
Bit 120: 1s = 0.497
Bit 119: 1s = 0.481
Bit 118: 1s = 0.502
Bit 117: 1s = 0.480
Bit 116: 1s = 0.520
Bit 115: 1s = 0.494
Bit 114: 1s = 0.510
Bit 113: 1s = 0.503
Bit 112: 1s = 0.503
Bit 111: 1s = 0.518
Bit 110: 1s = 0.511
Bit 109: 1s = 0.523
Bit 108: 1s = 0.497
Bit 107: 1s = 0.498
Bit 106: 1s = 0.506
Bit 105: 1s = 0.504
Bit 104: 1s = 0.478
Bit 103: 1s = 0.502
Bit 102: 1s = 0.505
Bit 101: 1s = 0.504
Bit 100: 1s = 0.469
Bit  99: 1s = 0.496
Bit  98: 1s = 0.513
Bit  97: 1s = 0.497
Bit  96: 1s = 0.510
Bit  95: 1s = 0.472
Bit  94: 1s = 0.498
Bit  93: 1s = 0.509
Bit  92: 1s = 0.478
Bit  91: 1s = 0.467
Bit  90: 1s = 0.514
Bit  89: 1s = 0.480
Bit  88: 1s = 0.497
Bit  87: 1s = 0.520
Bit  86: 1s = 0.497
Bit  85: 1s = 0.516
Bit  84: 1s = 0.484
Bit  83: 1s = 0.502
Bit  82: 1s = 0.467
Bit  81: 1s = 0.513
Bit  80: 1s = 0.494
Bit  79: 1s = 0.511
Bit  78: 1s = 0.512
Bit  77: 1s = 0.478
Bit  76: 1s = 0.485
Bit  75: 1s = 0.513
Bit  74: 1s = 0.500
Bit  73: 1s = 0.513
Bit  72: 1s = 0.496
Bit  71: 1s = 0.505
Bit  70: 1s = 0.496
Bit  69: 1s = 0.523
Bit  68: 1s = 0.512
Bit  67: 1s = 0.494
Bit  66: 1s = 0.489
Bit  65: 1s = 0.493
Bit  64: 1s = 0.510
Bit  63: 1s = 0.516
Bit  62: 1s = 0.513
Bit  61: 1s = 0.507
Bit  60: 1s = 0.495
Bit  59: 1s = 0.511
Bit  58: 1s = 0.500
Bit  57: 1s = 0.509
Bit  56: 1s = 0.488
Bit  55: 1s = 0.512
Bit  54: 1s = 0.500
Bit  53: 1s = 0.522
Bit  52: 1s = 0.512
Bit  51: 1s = 0.466
Bit  50: 1s = 0.489
Bit  49: 1s = 0.503
Bit  48: 1s = 0.497
Bit  47: 1s = 0.521
Bit  46: 1s = 0.513
Bit  45: 1s = 0.476
Bit  44: 1s = 0.519
Bit  43: 1s = 0.488
Bit  42: 1s = 0.492
Bit  41: 1s = 0.506
Bit  40: 1s = 0.538
Bit  39: 1s = 0.530
Bit  38: 1s = 0.501
Bit  37: 1s = 0.506
Bit  36: 1s = 0.528
Bit  35: 1s = 0.498
Bit  34: 1s = 0.503
Bit  33: 1s = 0.503
Bit  32: 1s = 0.500
Bit  31: 1s = 0.509
Bit  30: 1s = 0.501
Bit  29: 1s = 0.497
Bit  28: 1s = 0.486
Bit  27: 1s = 0.464
Bit  26: 1s = 0.525
Bit  25: 1s = 0.498
Bit  24: 1s = 0.511
Bit  23: 1s = 0.507
Bit  22: 1s = 0.493
Bit  21: 1s = 0.498
Bit  20: 1s = 0.470
Bit  19: 1s = 0.495
Bit  18: 1s = 0.502
Bit  17: 1s = 0.494
Bit  16: 1s = 0.510
Bit  15: 1s = 0.492
Bit  14: 1s = 0.490
Bit  13: 1s = 0.493
Bit  12: 1s = 0.500
Bit  11: 1s = 0.518
Bit  10: 1s = 0.490
Bit   9: 1s = 0.475
Bit   8: 1s = 0.505
Bit   7: 1s = 0.518
Bit   6: 1s = 0.511
Bit   5: 1s = 0.492
Bit   4: 1s = 0.498
Bit   3: 1s = 0.484
Bit   2: 1s = 0.531
Bit   1: 1s = 0.473
Bit   0: 1s = 0.495

  • Correlation Analysis:
Corr(R,Z): 0.0000
Corr(S,Z): -0.0000