Ming Ke Ming (名可名) -- Account Module (Python)
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
MKM(Default)BTCExtended BTCETHExtended ETH- ...
Public Key
A public key (PK) was bound 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:
- The length of name must more than 1 byte, less than 32 bytes;
- It should be composed by a-z, A-Z, 0-9, or charactors '_', '-', '.';
- 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.digest(SHA256.digest(fingerprint))
# 2. head = network + digest
head = bytes([network]) + 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 = data[0]
return cls(address=address, network=network)
def check_code(data: bytes) -> bytes:
# check code in BTC address
return SHA256.digest(SHA256.digest(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 error: %d' % len(fingerprint)
# 1. digest = keccak256(fingerprint)
digest = KECCAK256.digest(fingerprint)
# 2. address = hex_encode(digest.suffix(20))
tail = digest[-20:]
address = '0x' + eip55(address=Hex.encode(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.digest(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 encoded with BASE64 algorithm as default, excepts the address)
Metadata
Release files for mkm 2.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mkm-2.5.0.tar.gz | 39.0 kB | Without provenance | Details for mkm-2.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mkm-2.5.0-py3-none-any.whl | Python 3 | none | any | Details for mkm-2.5.0-py3-none-any.whl |
Total release size: 109.6 kB
Release files / mkm-2.5.0.tar.gz
| Download URL | mkm-2.5.0.tar.gz |
|---|---|
| Size | 39.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1e8d8c44b1897bb351a9a3b9e7303681f24402cd35f550a1171c271ad205e111
|
|
BLAKE2b-256 checksum How to use checksums |
9965c3e0883598525e85d0bc28fc06acfea0077368a33d8e360ad221f49c2c82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|
Release files / mkm-2.5.0-py3-none-any.whl
| Download URL | mkm-2.5.0-py3-none-any.whl |
|---|---|
| Size | 70.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b1693521853cf2cd56f756782b0e26c19a3bdae4a2cb0d327f40081b429e4b38
|
|
BLAKE2b-256 checksum How to use checksums |
46b639bb3bee1aa9caf13cc971bb30cd31061063f7e8c767f9a9685b9f74b7dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|
Security for mkm 2.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.