Saturday, December 28, 2024

python – What’s the chance of an ECDSA signature being lower than 71 bytes

The next Python program computes all of the attainable whole lengths as precisely as computationally possible:

from fractions import Fraction

P = 2**256 - 2**32 - 977
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

def lentable(desk, low, excessive):
    # For each worth v in [low, high], increment desk[l], the place l is the size
    # of the encoding of v. Returns the variety of values in vary.
    whole = 0
    whereas low <= excessive:
        lowlen = 1 + (low.bit_length() // 8)
        maxval = 2**(8*lowlen - 1) - 1
        highnow = min(excessive, maxval)
        whereas len(desk) <= lowlen:
            desk.append(0)
        desk[lowlen] += highnow - low + 1
        whole += highnow - low + 1
        low = highnow + 1
    return whole

def analyze(low_r, low_s):
    # Desk of chances of S size
    slen = []
    stotal = 0
    if low_s:
        stotal = lentable(slen, 1, N // 2)
        # Excessive s (vary n/2 + 1 .. N-1) is simply mapped to 1 .. N/2 once more.
    else:
        stotal = lentable(slen, 1, N-1)

    # Desk of chances of R size
    rlen = []
    rtotal = 0
    if low_r:
        rtotal = lentable(rlen, 0, 2**255-1)
        # Excessive r trigger a retry till one in 0..2**255-1 is hit.
    else:
        rtotal = lentable(rlen, 0, P-1)

    # Desk of signature lengths
    dlen = [0 for _ in range(len(slen) + len(rlen) + 5)]
    for sl in vary(len(slen)):
        for rl in vary(len(rlen)):
            dlen[sl + rl + 6] += Fraction(slen[sl] * rlen[rl], rtotal * stotal)

    return dlen

for low_r in [0, 1]:
    for low_s in [0, 1]:
        print("low_r=%i low_s=%i" % (low_r, low_s))
        for dl, freq in enumerate(analyze(low_r, low_s)):
            print("* siglen=%i: %.15g" % (dl, freq))
        print()

Its output incorporates:

low_r=0 low_s=0

  • siglen=64: 6.17568333711321e-15
  • siglen=65: 1.3553741462502e-12
  • siglen=66: 2.8922197969905e-10
  • siglen=67: 5.92558535572607e-08
  • siglen=68: 1.13845453597605e-05
  • siglen=69: 0.00194549560546875
  • siglen=70: 0.249996185302734
  • siglen=71: 0.498046875
  • siglen=72: 0.25

low_r=0 low_s=1

  • siglen=64: 1.23444548853768e-14
  • siglen=65: 2.7089788745549e-12
  • siglen=66: 5.77990988404053e-10
  • siglen=67: 1.18395746540045e-07
  • siglen=68: 2.27394048124552e-05
  • siglen=69: 0.00388339161872864
  • siglen=70: 0.498046875
  • siglen=71: 0.498046875

low_r=1 low_s=0

  • siglen=64: 1.23444548853768e-14
  • siglen=65: 2.7089788745549e-12
  • siglen=66: 5.77990988404053e-10
  • siglen=67: 1.18395746540045e-07
  • siglen=68: 2.27394048124552e-05
  • siglen=69: 0.00388339161872864
  • siglen=70: 0.498046875
  • siglen=71: 0.498046875

low_r=1 low_s=1

  • siglen=64: 2.46750861930545e-14
  • siglen=65: 5.41441891321881e-12
  • siglen=66: 1.15507603482001e-09
  • siglen=67: 2.36559571931139e-07
  • siglen=68: 4.54194378107786e-05
  • siglen=69: 0.00775158405303955
  • siglen=70: 0.992202758789062

The computation is finished with precise fractions, however printed as floating level. Change the “%.15g” to “%s” if you need fractions within the output.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles