Advertisement
joric

bitcoin signature verification script, ssl version

Jun 3rd, 2012
1,295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.54 KB | None | 0 0
  1. # -*- Mode: Python -*-
  2.  
  3. import ctypes
  4. import ctypes.util
  5. import hashlib
  6. import base64
  7. addrtype = 0
  8.  
  9. ssl = ctypes.cdll.LoadLibrary (ctypes.util.find_library ('ssl') or 'libeay32')
  10.  
  11. NID_secp256k1 = 714
  12.  
  13. def check_result (val, func, args):
  14.     if val == 0:
  15.         raise ValueError
  16.     else:
  17.         return ctypes.c_void_p (val)
  18.  
  19. ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
  20. ssl.EC_KEY_new_by_curve_name.errcheck = check_result
  21.  
  22. POINT_CONVERSION_COMPRESSED = 2
  23. POINT_CONVERSION_UNCOMPRESSED = 4
  24.  
  25. __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
  26. __b58base = len(__b58chars)
  27.  
  28. def b58encode(v):
  29.     """ encode v, which is a string of bytes, to base58.
  30.    """
  31.  
  32.     long_value = 0L
  33.     for (i, c) in enumerate(v[::-1]):
  34.         long_value += (256**i) * ord(c)
  35.  
  36.     result = ''
  37.     while long_value >= __b58base:
  38.         div, mod = divmod(long_value, __b58base)
  39.         result = __b58chars[mod] + result
  40.         long_value = div
  41.     result = __b58chars[long_value] + result
  42.  
  43.     # Bitcoin does a little leading-zero-compression:
  44.     # leading 0-bytes in the input become leading-1s
  45.     nPad = 0
  46.     for c in v:
  47.         if c == '\0': nPad += 1
  48.         else: break
  49.  
  50.     return (__b58chars[0]*nPad) + result
  51.  
  52. def hash_160(public_key):
  53.     md = hashlib.new('ripemd160')
  54.     md.update(hashlib.sha256(public_key).digest())
  55.     return md.digest()
  56.  
  57. def hash_160_to_bc_address(h160):
  58.     vh160 = chr(addrtype) + h160
  59.     h = Hash(vh160)
  60.     addr = vh160 + h[0:4]
  61.     return b58encode(addr)
  62.  
  63. def public_key_to_bc_address(public_key):
  64.     h160 = hash_160(public_key)
  65.     return hash_160_to_bc_address(h160)
  66.  
  67. def msg_magic(message):
  68.     return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message
  69.  
  70. def get_address(eckey):
  71.     size = ssl.i2o_ECPublicKey (eckey, 0)
  72.     mb = ctypes.create_string_buffer (size)
  73.     ssl.i2o_ECPublicKey (eckey, ctypes.byref (ctypes.pointer (mb)))
  74.     return public_key_to_bc_address(mb.raw)
  75.  
  76. def Hash(data):
  77.     return hashlib.sha256(hashlib.sha256(data).digest()).digest()
  78.  
  79. def bx(bn, size=32):
  80.     b = ctypes.create_string_buffer(size)
  81.     ssl.BN_bn2bin(bn, b);
  82.     return b.raw.encode('hex')
  83.  
  84. def verify_message(address, signature, message):
  85.     pkey = ssl.EC_KEY_new_by_curve_name (NID_secp256k1)
  86.     eckey = SetCompactSignature(pkey, Hash(msg_magic(message)), signature)
  87.     addr = get_address(eckey)
  88.     return (address == addr)
  89.  
  90. def SetCompactSignature(pkey, hash, signature):
  91.     sig = base64.b64decode(signature)
  92.     if len(sig) != 65:
  93.         raise BaseException("Wrong encoding")
  94.     nV = ord(sig[0])
  95.     if nV < 27 or nV >= 35:
  96.         return False
  97.     if nV >= 31:
  98.         ssl.EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED)
  99.         nV -= 4
  100.     r = ssl.BN_bin2bn (sig[1:33], 32, ssl.BN_new())
  101.     s = ssl.BN_bin2bn (sig[33:], 32, ssl.BN_new())
  102.     eckey = ECDSA_SIG_recover_key_GFp(pkey, r, s, hash, len(hash), nV - 27, False);
  103.     return eckey
  104.  
  105. def ECDSA_SIG_recover_key_GFp(eckey, r, s, msg, msglen, recid, check):
  106.     n = 0
  107.     i = recid / 2
  108.  
  109. #    print 'r', bx(r)
  110. #    print 's', bx(s)
  111. #    print 'd', recid
  112.  
  113.     group = ssl.EC_KEY_get0_group(eckey)
  114.     ctx = ssl.BN_CTX_new()
  115.     ssl.BN_CTX_start(ctx)
  116.     order = ssl.BN_CTX_get(ctx)
  117.     ssl.EC_GROUP_get_order(group, order, ctx)
  118.     x = ssl.BN_CTX_get(ctx)
  119.     ssl.BN_copy(x, order);
  120.     ssl.BN_mul_word(x, i);
  121.     ssl.BN_add(x, x, r)
  122.     field = ssl.BN_CTX_get(ctx)
  123.     ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx)
  124.  
  125.     if (ssl.BN_cmp(x, field) >= 0):
  126.         return False
  127.  
  128.     R = ssl.EC_POINT_new(group)
  129.     ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)
  130.  
  131.     if check:
  132.         O = ssl.EC_POINT_new(group)
  133.         ssl.EC_POINT_mul(group, O, None, R, order, ctx)
  134.         if ssl.EC_POINT_is_at_infinity(group, O):
  135.             return False
  136.  
  137.     Q = ssl.EC_POINT_new(group)
  138.     n = ssl.EC_GROUP_get_degree(group)
  139.     e = ssl.BN_CTX_get(ctx)
  140.     ssl.BN_bin2bn(msg, msglen, e)
  141.     if 8 * msglen > n: ssl.BN_rshift(e, e, 8 - (n & 7))
  142.  
  143.     print bx(e)
  144.  
  145.     zero = ssl.BN_CTX_get(ctx)
  146.     ssl.BN_set_word(zero, 0)
  147.     ssl.BN_mod_sub(e, zero, e, order, ctx)
  148.     rr = ssl.BN_CTX_get(ctx);
  149.     ssl.BN_mod_inverse(rr, r, order, ctx)
  150.     sor = ssl.BN_CTX_get(ctx)
  151.     ssl.BN_mod_mul(sor, s, rr, order, ctx)
  152.     eor = ssl.BN_CTX_get(ctx)
  153.     ssl.BN_mod_mul(eor, e, rr, order, ctx)
  154.     ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx)
  155.     ssl.EC_KEY_set_public_key(eckey, Q)
  156.     return eckey
  157.  
  158. if __name__ == '__main__':
  159.     # some simple testing code
  160.     print verify_message('16vqGo3KRKE9kTsTZxKoJKLzwZGTodK3ce',
  161.             'HPDs1TesA48a9up4QORIuub67VHBM37X66skAYz0Esg23gdfMuCTYDFORc6XGpKZ2/flJ2h/DUF569FJxGoVZ50=',
  162.             'test message') # good
  163.     print verify_message('16vqGo3KRKE9kTsTZxKoJKLzwZGTodK3ce',
  164.             'HPDs1TesA48a9up4QORIuub67VHBM37X66skAYz0Esg23gdfMuCTYDFORc6XGpKZ2/flJ2h/DUF569FJxGoVZ50=',
  165.             'test message 2') # bad
  166.     print verify_message('1GdKjTSg2eMyeVvPV5Nivo6kR8yP2GT7wF',
  167.             'GyMn9AdYeZIPWLVCiAblOOG18Qqy4fFaqjg5rjH6QT5tNiUXLS6T2o7iuWkV1gc4DbEWvyi8yJ8FvSkmEs3voWE=',
  168.             'freenode:#bitcoin-otc:b42f7e7ea336db4109df6badc05c6b3ea8bfaa13575b51631c5178a7')
  169.     print verify_message('1Hpj6xv9AzaaXjPPisQrdAD2tu84cnPv3f','INEJxQnSu6mwGnLs0E8eirl5g+0cAC9D5M7hALHD9sK0XQ66CH9mas06gNoIX7K1NKTLaj3MzVe8z3pt6apGJ34=','testtest')
  170.     print verify_message('18uitB5ARAhyxmkN2Sa9TbEuoGN1he83BX','IMAtT1SjRyP6bz6vm5tKDTTTNYS6D8w2RQQyKD3VGPq2i2txGd2ar18L8/nvF1+kAMo5tNc4x0xAOGP0HRjKLjc=','testtest')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement