# -*- Mode: Python -*- # OpenSSL wrapper import ctypes import ctypes.util ssl = ctypes.cdll.LoadLibrary (ctypes.util.find_library ('ssl') or 'libeay32') # this specifies the curve used with ECDSA. NID_secp256k1 = 714 # from openssl/obj_mac.h # Thx to Sam Devlin for the ctypes magic 64-bit fix. def check_result (val, func, args): if val == 0: raise ValueError else: return ctypes.c_void_p (val) ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p ssl.EC_KEY_new_by_curve_name.errcheck = check_result class KEY: def __init__(self): self.POINT_CONVERSION_COMPRESSED = 2 self.POINT_CONVERSION_UNCOMPRESSED = 4 self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1) def __del__(self): if ssl: ssl.EC_KEY_free(self.k) self.k = None def generate(self, secret=None): if secret: self.prikey = secret priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new()) group = ssl.EC_KEY_get0_group(self.k) pub_key = ssl.EC_POINT_new(group) ctx = ssl.BN_CTX_new() ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx) ssl.EC_KEY_set_private_key(self.k, priv_key) ssl.EC_KEY_set_public_key(self.k, pub_key) ssl.EC_POINT_free(pub_key) ssl.BN_CTX_free(ctx) return self.k else: return ssl.EC_KEY_generate_key(self.k) def set_privkey(self, key): self.mb = ctypes.create_string_buffer(key) ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) def set_pubkey(self, key): self.mb = ctypes.create_string_buffer(key) ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) def get_privkey(self): size = ssl.i2d_ECPrivateKey(self.k, 0) mb_pri = ctypes.create_string_buffer(size) ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri))) return mb_pri.raw def get_pubkey(self): size = ssl.i2o_ECPublicKey(self.k, 0) mb = ctypes.create_string_buffer(size) ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb))) return mb.raw def sign(self, hash): sig_size = ssl.ECDSA_size(self.k) mb_sig = ctypes.create_string_buffer(sig_size) sig_size0 = ctypes.c_uint32() assert 1 == ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k) return mb_sig.raw[:sig_size0.value] def verify(self, hash, sig): return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) def set_compressed(self, compressed): if compressed: form = self.POINT_CONVERSION_COMPRESSED else: form = self.POINT_CONVERSION_UNCOMPRESSED ssl.EC_KEY_set_conv_form(self.k, form) def get_secret(self): bn = ssl.EC_KEY_get0_private_key(self.k) mb = ctypes.create_string_buffer(32) ssl.BN_bn2bin(bn, mb) return mb.raw if __name__ == '__main__': # ethalone keys ec_secret = '' + \ 'a0dc65ffca799873cbea0ac274015b9526505daaaed385155425f7337704883e' ec_private = '308201130201010420' + \ 'a0dc65ffca799873cbea0ac274015b9526505daaaed385155425f7337704883e' + \ 'a081a53081a2020101302c06072a8648ce3d0101022100' + \ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' + \ '300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2d' + \ 'ce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a6' + \ '8554199c47d08ffb10d4b8022100' + \ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + \ '020101a14403420004' + \ '0791dc70b75aa995213244ad3f4886d74d61ccd3ef658243fcad14c9ccee2b0a' + \ 'a762fbc6ac0921b8f17025bb8458b92794ae87a133894d70d7995fc0b6b5ab90' k = KEY() k.generate (ec_secret.decode('hex')) k.set_compressed(True) print k.get_privkey ().encode('hex') print k.get_pubkey().encode('hex') print k.get_secret().encode('hex')