Skip to main content

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.

Features

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. ...

Public Key

A public key (PK) was binded to an ID by the Meta Algorithm.

Seed

A string as same as ID.name for generate the fingerprint.

Fingerprint

THe fingerprint field was generated by your private key and seed:

data = utf8_encode(string=seed);
fingerprint = private_key.sign(data=data);

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 Type

class EntityType(IntEnum):
    
    ################################
    #  Main: 0, 1
    ################################
    USER = 0x00             # 0000 0000
    GROUP = 0x01            # 0000 0001 (User Group)

    ################################
    #  Network: 2, 3
    ################################
    STATION = 0x02          # 0000 0010 (Server Node)
    ISP = 0x03              # 0000 0011 (Service Provider)
    # STATION_GROUP = 0x03  # 0000 0011

    ################################
    #  Bot: 4, 5
    ################################
    BOT = 0x04              # 0000 0100 (Business Node)
    ICP = 0x05              # 0000 0101 (Content Provider)
    # BOT_GROUP = 0x05      # 0000 0101

    ################################
    #  Management: 6, 7, 8
    ################################
    # SUPERVISOR = 0x06     # 0000 0110 (Company CEO)
    # COMPANY = 0x07        # 0000 0111 (Super Group for ISP/ICP)
    # CA = 0x08             # 0000 1000 (Certification Authority)

    ################################
    #  Customized: 64, 65
    ################################
    # APP_USER = 0x40       # 0100 0000 (Application Customized User)
    # APP_GROUP = 0x41      # 0100 0001 (Application Customized Group)

    ################################
    #  Broadcast: 128, 129
    ################################
    ANY = 0x80              # 1000 0000 (anyone@anywhere)
    EVERY = 0x81            # 1000 0001 (everyone@everywhere)

    @classmethod
    def is_user(cls, network: int) -> bool:
        return (network & cls.GROUP) == cls.USER

    @classmethod
    def is_group(cls, network: int) -> bool:
        return (network & cls.GROUP) == cls.GROUP

    @classmethod
    def is_broadcast(cls, network: int) -> bool:
        return (network & cls.ANY) == cls.ANY

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 import *


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 import *


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.

Terminal

A resource identifier as Login Point.

Samples

ID examples

ID1 = "hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj"  # Immortal Hulk
ID2 = "moki@4WDfe3zZ4T7opFSi3iDAKiuTnUHjxmXekk"  # Monkey King

Meta Example (JsON) for hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj

{
    "type"        : "1",
    "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="
}

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


Copyright © 2018-2026 Albert Moky Followers

Download files

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

Source Distribution

mkm-2.4.3.tar.gz (33.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mkm-2.4.3-py3-none-any.whl (65.0 kB view details)

Uploaded Python 3

File details

Details for the file mkm-2.4.3.tar.gz.

File metadata

  • Download URL: mkm-2.4.3.tar.gz
  • Upload date:
  • Size: 33.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/68.0.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.0b3

File hashes

Hashes for mkm-2.4.3.tar.gz
Algorithm Hash digest
SHA256 ae2d1b5b6aa8bc1d7051a7a01a9dc1d61c85161b38daeb2167d6bd515d56a6f0
MD5 e13887a08bcfad93569ee010ebcf2343
BLAKE2b-256 b844ace569296489e45c78f19e901dd655c91f282e362422c9060fc8ab6c0358

See more details on using hashes here.

File details

Details for the file mkm-2.4.3-py3-none-any.whl.

File metadata

  • Download URL: mkm-2.4.3-py3-none-any.whl
  • Upload date:
  • Size: 65.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/68.0.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.0b3

File hashes

Hashes for mkm-2.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7ba3826bc4d6f47498e2892507f012749aabd063cd728d1a39101f5a7052d9c5
MD5 422388f88ce39007675cac65cf06bf78
BLAKE2b-256 395efaee75fc828759fa7857305fac606d9a0e3723e39af9c04ecabfcab32eb7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2.4.3 This release

2 files

2.4.2

2 files

2.4.1

2 files

2.4.0

2 files

2.3.4

2 files

2.3.3

2 files

2.3.2

2 files

2.3.1

2 files

2.3.0

2 files

2.2.2

2 files

2.2.1

2 files

2.2.0

2 files

2.1.0

2 files

2.0.0

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.12.8

2 files

0.12.7

2 files

0.12.6

2 files

0.12.4

2 files

0.12.3

2 files

0.12.2

2 files

0.12.1

2 files

0.12.0

2 files

0.11.6

2 files

0.11.5

2 files

0.11.2

2 files

0.11.1

2 files

0.10.15

2 files

0.10.13

2 files

0.10.12

2 files

0.10.11

2 files

0.10.10

2 files

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.8.10

2 files

0.8.9

2 files

0.8.8

2 files

0.8.6

2 files

0.8.5

2 files

0.8.4

2 files

0.8.3

2 files

0.8.2

2 files

0.7.12

2 files

0.7.11

2 files

0.7.10

2 files

0.7.9

2 files

0.7.7

2 files

0.7.6

2 files

0.7.5

2 files

0.7.3

2 files

0.7.1

2 files

0.7.0

2 files

0.6.19

2 files

0.6.18

2 files

0.6.13

2 files

0.6.10

2 files

0.6.9

2 files

0.6.8

2 files

0.6.7

2 files

0.6.6

2 files

0.6.5

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.12

2 files

0.5.11

2 files

0.5.10

2 files

0.5.9

2 files

0.5.8

2 files

0.5.7

2 files

0.5.6

2 files

0.5.5

2 files

0.4.3

2 files

0.4.2

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page