Skip to content

dimchat/mkm-py

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ming Ke Ming (名可名) -- Account Module (Python)

License PRs Welcome Platform Issues Repo Size Tags Version

Watchers Forks Stars Followers

This document introduces a common Account Module for decentralized user identity authentication.

Meta

The Meta was generated by your private key, it can be used to build a new ID for entity, or verify the ID/PK pair.

It consists of 4 fields:

Field Description
type Algorithm Version
key Public Key
seed Entity Name (Optional)
fingerprint Signature to generate address (Optional)

If seed exists, fingerprint = private_key.sign(seed)

Meta Type

  1. MKM (Default)
  2. BTC
  3. Extended BTC
  4. ETH
  5. Extended ETH
  6. ...

Meta Example

/* Meta(JsON) for hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj */
{
    "type"        : 0x01,
    "key"         : {
        "algorithm" : "RSA",
        "data"      : "-----BEGIN PUBLIC KEY-----\nMIGJAoGBALB+vbUK48UU9rjlgnohQowME+3JtTb2hLPqtatVOW364/EKFq0/PSdnZVE9V2Zq+pbX7dj3nCS4pWnYf40ELH8wuDm0Tc4jQ70v4LgAcdy3JGTnWUGiCsY+0Z8kNzRkm3FJid592FL7ryzfvIzB9bjg8U2JqlyCVAyUYEnKv4lDAgMBAAE=\n-----END PUBLIC KEY-----",
        "mode"      : "ECB",
        "padding"   : "PKCS1",
        "digest"    : "SHA256"
    },
    "seed"        : "hulk",
    "fingerprint" : "jIPGWpWSbR/DQH6ol3t9DSFkYroVHQDvtbJErmFztMUP2DgRrRSNWuoKY5Y26qL38wfXJQXjYiWqNWKQmQe/gK8M8NkU7lRwm+2nh9wSBYV6Q4WXsCboKbnM0+HVn9Vdfp21hMMGrxTX1pBPRbi0567ZjNQC8ffdW2WvQSoec2I="
}

ID

The ID is used to identify an entity(user/group). It consists of 3 fields:

Field Description
type Entity type
name Same with meta.seed (Optional)
address Unique Identification
terminal Login point (Optional)

The ID format is name@address[/terminal].

# ID examples
ID1 = "hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj";  // Immortal Hulk
ID2 = "moki@4WDfe3zZ4T7opFSi3iDAKiuTnUHjxmXekk";  // Monkey King

ID Name

The Name field is a username, or just a random string for group:

  1. The length of name must more than 1 byte, less than 32 bytes;
  2. It should be composed by a-z, A-Z, 0-9, or charactors '_', '-', '.';
  3. It cannot contain key charactors('@', '/').
# Name examples
user_name  = "Albert.Moky";
group_name = "Group-9527";

It's equivalent to meta.seed

ID Address

The Address field was created with the Meta and a Network ID:

BTC Address

from typing import Optional

from mkm.types import ConstantString
from mkm.digest import sha256, ripemd160
from mkm.format import base58_encode, base58_decode
from mkm import Address


class BTCAddress(ConstantString, Address):
    """
        Address like BitCoin
        ~~~~~~~~~~~~~~~~~~~~

        data format: "network+digest+code"
            network    --  1 byte
            digest     -- 20 bytes
            check code --  4 bytes

        algorithm:
            fingerprint = PK.data
            digest      = ripemd160(sha256(fingerprint));
            code        = sha256(sha256(network + digest)).prefix(4);
            address     = base58_encode(network + digest + code);
    """

    def __init__(self, address: str, network: int):
        super().__init__(string=address)
        self.__type = network

    @property  # Override
    def network(self) -> int:
        return self.__type

    #
    #   Factory methods
    #
    @classmethod
    def from_data(cls, fingerprint: bytes, network: int) -> Address:
        """
        Generate address with fingerprint and network ID

        :param fingerprint: meta.fingerprint or key.data
        :param network:     address type
        :return: Address object
        """
        # 1. digest = ripemd160(sha256(fingerprint))
        digest = ripemd160(sha256(fingerprint))
        # 2. head = network + digest
        head = chr(network).encode('latin1') + digest
        # 3. cc = sha256(sha256(head)).prefix(4)
        code = check_code(head)
        # 4. data = base58_encode(head + cc)
        address = base58_encode(head + code)
        return cls(address=address, network=network)

    @classmethod
    def from_str(cls, address: str) -> Optional[Address]:
        """
        Parse a string for BTC address

        :param address: address string
        :return: Address object
        """
        if len(address) < 26 or len(address) > 35:
            return None
        # decode
        data = base58_decode(address)
        if data is None or len(data) != 25:
            return None
        # check code
        prefix = data[:21]
        suffix = data[21:]
        if check_code(prefix) == suffix:
            network = ord(data[:1])
            return cls(address=address, network=network)


def check_code(data: bytes) -> bytes:
    # check code in BTC address
    return sha256(sha256(data))[:4]

ETH Address

from typing import Optional

from mkm.types import ConstantString
from mkm.digest import keccak256
from mkm.format import hex_encode
from mkm import Address, EntityType

class ETHAddress(ConstantString, Address):
    """
        Address like Ethereum
        ~~~~~~~~~~~~~~~~~~~~~

        data format: "0x{address}"

        algorithm:
            fingerprint = PK.data
            digest      = keccak256(fingerprint)
            address     = hex_encode(digest.suffix(20))
    """

    def __init__(self, address: str):
        super().__init__(string=address)

    @property  # Override
    def network(self) -> int:
        return EntityType.USER.value

    @classmethod
    def validate_address(cls, address: str) -> Optional[str]:
        if is_eth(address=address):
            lower = address[2:].lower()
            return '0x%s' % eip55(address=lower)
        # not an ETH address

    @classmethod
    def is_validate(cls, address: str) -> bool:
        validate = cls.validate_address(address=address)
        return validate is not None and validate == address

    #
    #   Factory methods
    #
    @classmethod
    def from_data(cls, fingerprint: bytes) -> Address:
        """
        Generate ETH address with key.data

        :param fingerprint: key.data
        :return: Address object
        """
        if len(fingerprint) == 65:
            # skip first char
            fingerprint = fingerprint[1:]
        assert len(fingerprint) == 64, 'key data length error: %d' % len(fingerprint)
        # 1. digest = keccak256(fingerprint)
        digest = keccak256(data=fingerprint)
        # 2. address = hex_encode(digest.suffix(20))
        tail = digest[-20:]
        address = '0x' + eip55(address=hex_encode(data=tail))
        return cls(address=address)

    @classmethod
    def from_str(cls, address: str) -> Optional[Address]:
        """
        Parse a string for ETH address

        :param address: address string
        :return: Address object
        """
        if is_eth(address=address):
            return cls(address=address)


# https://eips.ethereum.org/EIPS/eip-55
def eip55(address: str) -> str:
    res = ''
    table = keccak256(address.encode('utf-8'))
    for i in range(40):
        ch = address[i]
        x = ord(ch)
        if x > 0x39:
            # check for each 4 bits in the hash table
            # if the first bit is '1',
            #     change the character to uppercase
            x -= (table[i >> 1] << (i << 2 & 4) & 0x80) >> 2
            ch = chr(x)
        res += ch
    return res


def is_eth(address: str) -> bool:
    if len(address) != 42:
        return False
    if address[0] != '0' or address[1] != 'x':
        return False
    for i in range(2, 42):
        ch = address[i]
        if '0' <= ch <= '9':
            continue
        if 'A' <= ch <= 'Z':
            continue
        if 'a' <= ch <= 'z':
            continue
        # unexpected character
        return False
    return True

When you get a meta for the entity ID from the network, you must verify it with the consensus algorithm before accepting its public key.

(All data encode with BASE64 algorithm as default, excepts the address)


Copyright © 2018-2025 Albert Moky Followers

About

Ming Ke Ming (名可名) -- Account Module

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages