diff --git a/cython/.gitignore b/cython/.gitignore new file mode 100644 index 000000000..feaa147ef --- /dev/null +++ b/cython/.gitignore @@ -0,0 +1,2 @@ +build/ +*.c diff --git a/cython/TrezorCrypto.pyx b/cython/TrezorCrypto.pyx new file mode 100644 index 000000000..17e3f8f01 --- /dev/null +++ b/cython/TrezorCrypto.pyx @@ -0,0 +1,38 @@ +cimport c +cimport cython + +cdef class HDNode: + + cdef c.HDNode node + + def __init__(self, initializer): + if isinstance(initializer, HDNode): + self.node = (initializer).node + elif isinstance(initializer, str) : + if c.hdnode_deserialize(initializer, cython.address(self.node)) != 0: + raise Exception('Invalid xpub/xprv provided') + + def xpub(self): + cdef char[120] string + c.hdnode_serialize_public(cython.address(self.node), string, 120) + return str(string) + + def xprv(self): + cdef char[120] string + c.hdnode_serialize_private(cython.address(self.node), string, 120) + return str(string) + + def address(self): + cdef char[40] string + c.ecdsa_get_address(self.node.public_key, 0, string, 40) + return str(string) + + def public_ckd(self, int i): + x = HDNode(self) + c.hdnode_public_ckd(cython.address(x.node), i) + return x + + def private_ckd(self, int i): + x = HDNode(self) + c.hdnode_private_ckd(cython.address(x.node), i) + return x diff --git a/cython/c.pxd b/cython/c.pxd new file mode 100644 index 000000000..2e85d8ef4 --- /dev/null +++ b/cython/c.pxd @@ -0,0 +1,22 @@ +from libc.stdint cimport uint32_t, uint8_t + +cdef extern from "../bip32.h": + + ctypedef struct HDNode: + uint8_t public_key[33] + + int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) + + int hdnode_private_ckd(HDNode *inout, uint32_t i) + + int hdnode_public_ckd(HDNode *inout, uint32_t i) + + void hdnode_serialize_public(const HDNode *node, char *str, int strsize) + + void hdnode_serialize_private(const HDNode *node, char *str, int strsize) + + int hdnode_deserialize(const char *str, HDNode *node) + +cdef extern from "../ecdsa.h": + + void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) diff --git a/cython/setup.py b/cython/setup.py new file mode 100644 index 000000000..dec830a7f --- /dev/null +++ b/cython/setup.py @@ -0,0 +1,36 @@ +from distutils.core import setup +from distutils.extension import Extension +from Cython.Build import cythonize +from Cython.Distutils import build_ext + +crypto_srcs = [ + 'base58.c', + 'bignum.c', + 'bip32.c', + 'ecdsa.c', + 'hmac.c', + 'rand.c', + 'ripemd160.c', + 'secp256k1.c', + 'sha2.c', +] + +crypto_srcs = [ '../%s' % x for x in crypto_srcs ] + +extensions = [ + Extension('TrezorCrypto', + sources = ['TrezorCrypto.pyx', 'c.pxd'] + crypto_srcs, + extra_compile_args = ['-DUSE_PUBKEY_VALIDATE=0'], + ) +] + +setup( + name = 'TrezorCrypto', + version = '0', + description = 'Cython wrapper around trezor-crypto library', + author = 'Pavol Rusnak', + author_email = 'stick@satoshilabs.com', + url = 'https://github.com/trezor/trezor-crypto', + cmdclass = {'build_ext': build_ext}, + ext_modules = cythonize(extensions), +) diff --git a/cython/test.py b/cython/test.py new file mode 100755 index 000000000..088616d22 --- /dev/null +++ b/cython/test.py @@ -0,0 +1,10 @@ +#!/usr/bin/python +from TrezorCrypto import HDNode + +x = HDNode('xpub6BcjTvRCYD4VvFQ8whztSXhbNyhS56eTd5P3g9Zvd3zPEeUeL5CUqBYX8NSd1b6Thitr8bZcSnesmXZH7KerMcc4tUkenBShYCtQ1L8ebVe') + +y = x.public_ckd(0) + +for i in range(1000): + z = y.public_ckd(i) + print i, z.address()