exec('row2["' + key + '"] = ' + val) # int means no quote else: exec('row2["' + key + '"] = "' + val + '"') # str means quote if key != 'm': continue #### Find repeated r row1 = first_row_where('r', row2['r'], all_past) if not row1: all_past.append(row2) continue #### get cracking m1 = int(row1['m'], 16) m2 = int(row2['m'], 16) k = ((m1 - m2) * invmod((row1['s'] - row2['s']), q) % q) print "k =", k x = find_private_key(row1['r'], row1['s'], k, m1, q) print "x =", x hex_x = hex(x).replace('0x', '').replace('L', '') s1x = sha1(hex_x).hexdigest() print "sha1(x) =", s1x break #### tests #### h = [{ 'a': 10, 'b': 9, 'c': 4 }, { 'a': 777, 'b': 99, 'c': 42
print "r =", r print "s =", s print #### Breaking, given a signature [r,s], and given that k <= 2**16. #### Also of course given parameters g, p, q, and hash H of message. print "Searching for k (nonce, subkey) and thus x (private key)...." matasano_r = 548099063082341131477253921760299949438196259240 matasano_s = 857042759984254168557880549501802188789837994940 k_found = 0 x_found = 0 start = time.time() for k in range(1, 2**16): r = pow(g, k, p) % q x = find_private_key(matasano_r, matasano_s, k, H, q) s = ((H + x * r) * invmod(k, q)) % q if s == matasano_s and r == matasano_r: print "k =", k print "x =", x k_found = k x_found = x # Deciding not to break out of the for loop, in rare event # there would be two valid values of k. end = time.time() dur = end - start rate = k / dur print "Tried", k, "nonces in", int(dur), "s, for", int(rate), "per s." # 5800 per sec on MacBook Pro 8,1 (early 2011, OS X, 2.7 GHz Intel Core i7) S = hex(x_found).replace("L", "").replace("0x", "")