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.11.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

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

Uploaded Python 3

File details

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

File metadata

  • Download URL: xchainpy_crypto-0.1.11.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.11.tar.gz
Algorithm Hash digest
SHA256 5f1adba9f5ee31e167391db7a68f8bf4a72579a2acca6173594d976f335cf19a
MD5 b6392d8fbbaf490cdee69b088a2fccfd
BLAKE2b-256 c1173467f986b14ef81b216178bac5b8012d2469e1ac9837002f0ed77407e9c5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xchainpy_crypto-0.1.11-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.11-py3-none-any.whl
Algorithm Hash digest
SHA256 e1b1d481ec1881d5581579a512404d0f3afbc7db2eb82b7e30c18d57c659c3ba
MD5 e656359c7902abf594fc4a0d728f8515
BLAKE2b-256 b926139878014492efc0ae24932410abe06fb94e7e2288c69f0cdf8be064de01

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