Skip to main content

XCHAIN-CRYPTO encrypts a master phrase to a keystore

Project description

XCHAIN-CRYPTO

The XCHAIN CRYPTO package is a crypto package used by all XCHAIN clients.

XCHAIN-CRYPTO encrypts a master phrase to a keystore. This keystore can then be exported to other XCHAIN wallets or stored securely.

Users can export their phrase and import them into other wallets since it is a BIP39 compatible phrase.

Design

Typically keystore files encrypt a seed to a file, however this is not appropriate or UX friendly, since the phrase cannot be recovered after the fact.

Crypto design:

[entropy] -> [phrase] -> [seed] -> [privateKey] -> [publicKey] -> [address]

Instead, XCHAIN-CRYPTO stores the phrase in a keystore file, then decrypts and passes this phrase to other clients:

[keystore] -> XCHAIN-CRYPTO -> [phrase] -> ChainClient

The ChainClients can then convert this into their respective key-pairs and addresses. Users can also export their phrases after the fact, ensuring they have saved it securely. This could enhance UX onboarding since users aren't forced to write their phrases down immediately for empty or test wallets.

# Crypto Constants for xchain
CIPHER = AES.MODE_CTR
NBITS = 128
KDF = "pbkdf2"
PRF = "hmac-sha256"
DKLEN = 32
C = 262144
HASHFUNCTION = SHA256
META = "xchain-keystore"

Installation

pip install xchainpy_crypto

Before install the package on M1 Mac, execute this command:

brew install autoconf automake libffi libtool pkg-config

Usage

Basic usage

from xchainpy_crypto.crypto import validate_phrase, encrypt_to_keystore, decrypt_from_keystore, generate_mnemonic

phrase = generate_mnemonic(size=12, language='english')
print(phrase)
is_correct = validate_phrase(phrase)
print(is_correct)
password = 'thorchain'
keystore = await encrypt_to_keystore(phrase, password)
phrase_decrypted = await decrypt_from_keystore(keystore, password)
print(phrase_decrypted)

Keystore Model

class Keystore:
    def __init__(self, crypto:CryptoStruct, id:str, version:int, meta:str):
        self._crypto = crypto
        self._id = id
        self._version = version
        self._meta = meta

    @classmethod
    def from_dict(cls, keystore):
        new_keystore = cls.__new__(cls)
        for key in keystore:
            setattr(new_keystore, key, keystore[key])
        return new_keystore

    @property
    def crypto(self):
        return self._crypto

    @crypto.setter
    def crypto(self, crypto):
        if isinstance(crypto, dict):
            self._crypto = CryptoStruct.from_dict(crypto)
        else:
            self._crypto = crypto

    @property
    def id(self):
        return self._id

    @id.setter
    def id(self, id):
        self._id = id

    @property
    def version(self):
        return self._version

    @version.setter
    def version(self, version):
        self._version = version

    @property
    def meta(self):
        return self._meta

    @meta.setter
    def meta(self, meta):
        self._meta = meta

    def to_json(self):
        return json.dumps(self, default=lambda o: {key.lstrip('_'): value for key, value in o.__dict__.items()})

CipherParams

class CipherParams:
    def __init__(self, iv:str):
        self._iv = iv

    @classmethod
    def from_dict(cls, cipherparams):
        new_cipherparams = cls.__new__(cls)
        for key in cipherparams:
            setattr(new_cipherparams, key, cipherparams[key])
        return new_cipherparams

    @property
    def iv(self):
        return self._iv

    @iv.setter
    def iv(self, iv):
        self._iv = iv

CryptoStruct

class CryptoStruct:
    def __init__(
        self,
        cipher: int,
        ciphertext: str,
        cipherparams: CipherParams,
        kdf: str,
        kdfparams: KdfParams,
        mac: str,
    ):
        self._cipher = cipher
        self._ciphertext = ciphertext
        self._cipherparams = cipherparams
        self._kdf = kdf
        self._kdfparams = kdfparams
        self._mac = mac

    @classmethod
    def from_dict(cls, crypto):
        new_crypto = cls.__new__(cls)
        for key in crypto:
            setattr(new_crypto, key, crypto[key])
        return new_crypto

    @property
    def cipher(self):
        return self._cipher

    @cipher.setter
    def cipher(self, cipher):
        self._cipher = cipher

    @property
    def ciphertext(self):
        return self._ciphertext

    @ciphertext.setter
    def ciphertext(self, ciphertext):
        self._ciphertext = ciphertext

    @property
    def cipherparams(self):
        return self._cipherparams

    @cipherparams.setter
    def cipherparams(self, cipherparams):
        if isinstance(cipherparams, dict):
            self._cipherparams = CipherParams.from_dict(cipherparams)
        else:
            self._cipherparams = cipherparams

    @property
    def kdf(self):
        return self._kdf

    @kdf.setter
    def kdf(self, kdf):
        self._kdf = kdf

    @property
    def kdfparams(self):
        return self._kdfparams

    @kdfparams.setter
    def kdfparams(self, kdfparams):
        if isinstance(kdfparams, dict):
            self._kdfparams = KdfParams.from_dict(kdfparams)
        else:
            self._kdfparams = kdfparams

    @property
    def mac(self):
        return self._mac

    @mac.setter
    def mac(self, mac):
        self._mac = mac

KdfParams

class KdfParams:
    def __init__(self, prf:str , dklen:int , salt:str , c:int):
        self._prf = prf
        self._dklen = dklen
        self._salt = salt
        self._c = c

    @classmethod
    def from_dict(cls, kdfparams):
        new_kdfparams = cls.__new__(cls)
        for key in kdfparams:
            setattr(new_kdfparams, key, kdfparams[key])
        return new_kdfparams
    
    @property
    def prf(self):
        return self._prf

    @prf.setter
    def prf(self, prf):
        self._prf = prf

    @property
    def dklen(self):
        return self._dklen
    
    @dklen.setter
    def dklen(self, dklen):
        self._dklen = dklen
    
    @property
    def salt(self):
        return self._salt

    @salt.setter
    def salt(self, salt):
        self._salt = salt

    @property
    def c(self):
        return self._c

    @c.setter
    def c(self, c):
        self._c = c

Tests

These packages needed to run tests:

  • pytest pip install pytest
  • pytest-asyncio pip install pytest-asyncio

How to run test ?

$ python -m pytest xchainpy/xchainpy_crypto/tests

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xchainpy_crypto-0.1.9.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

xchainpy_crypto-0.1.9-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file xchainpy_crypto-0.1.9.tar.gz.

File metadata

  • Download URL: xchainpy_crypto-0.1.9.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.2

File hashes

Hashes for xchainpy_crypto-0.1.9.tar.gz
Algorithm Hash digest
SHA256 9953b79bb3c44b2b10104585a5e743ebd09969defadd5553a74c1112bb09d4c0
MD5 b6c51ef3476f0e1416094b0d68d4064b
BLAKE2b-256 56dd52d6243fbb55aec55a982ada382558c6e99db283336bf47e8da447a3003c

See more details on using hashes here.

File details

Details for the file xchainpy_crypto-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: xchainpy_crypto-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.2

File hashes

Hashes for xchainpy_crypto-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 dffe19500578ab3e28342137af21704c69010495f4daf6da417c7d33078a0568
MD5 09f1dc660f7a64b6ce11e1b7298e18f0
BLAKE2b-256 f7eb5741be98c10f277a6803e7ac5a2686a13ef5597dc9b9a69c6e3f4761894e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page