{"id":32311648,"url":"https://github.com/dimchat/mkm-objc","last_synced_at":"2026-02-22T01:39:09.237Z","repository":{"id":56932731,"uuid":"162410689","full_name":"dimchat/mkm-objc","owner":"dimchat","description":"Ming Ke Ming (名可名) -- Account Module","archived":false,"fork":false,"pushed_at":"2026-01-02T17:57:07.000Z","size":980,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-09T01:29:04.185Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dimchat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-12-19T09:01:24.000Z","updated_at":"2026-01-02T17:57:11.000Z","dependencies_parsed_at":"2023-12-07T09:28:45.719Z","dependency_job_id":"ccd0654a-def0-441b-9e98-840a8072a578","html_url":"https://github.com/dimchat/mkm-objc","commit_stats":{"total_commits":196,"total_committers":3,"mean_commits":65.33333333333333,"dds":0.04591836734693877,"last_synced_commit":"b60ebcac91d5a7b37a6a6668b4307d7ac5231bf6"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/dimchat/mkm-objc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimchat%2Fmkm-objc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimchat%2Fmkm-objc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimchat%2Fmkm-objc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimchat%2Fmkm-objc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dimchat","download_url":"https://codeload.github.com/dimchat/mkm-objc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimchat%2Fmkm-objc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29703227,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T23:35:04.139Z","status":"ssl_error","status_checked_at":"2026-02-21T23:35:03.832Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-23T09:38:46.696Z","updated_at":"2026-02-22T01:39:09.231Z","avatar_url":"https://github.com/dimchat.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ming Ke Ming (名可名) -- Account Module (Objective-C)\n\n[![License](https://img.shields.io/github/license/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/blob/master/LICENSE)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/dimchat/mkm-objc/pulls)\n[![Platform](https://img.shields.io/badge/Platform-iOS%20%7C%20OSX%20%7C%20watchOS%20%7C%20tvOS-brightgreen.svg)](https://github.com/dimchat/mkm-objc/wiki)\n[![Issues](https://img.shields.io/github/issues/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/issues)\n[![Repo Size](https://img.shields.io/github/repo-size/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/archive/refs/heads/master.zip)\n[![Tags](https://img.shields.io/github/tag/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/tags)\n[![Version](https://img.shields.io/cocoapods/v/MingKeMing\n)](https://cocoapods.org/pods/MingKeMing)\n\n[![Watchers](https://img.shields.io/github/watchers/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/watchers)\n[![Forks](https://img.shields.io/github/forks/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/forks)\n[![Stars](https://img.shields.io/github/stars/dimchat/mkm-objc)](https://github.com/dimchat/mkm-objc/stargazers)\n[![Followers](https://img.shields.io/github/followers/dimchat)](https://github.com/orgs/dimchat/followers)\n\nThis [document](https://github.com/moky/DIMP/blob/master/MingKeMing-Identity.md) introduces a common **Account Module** for decentralized user identity authentication.\n\n## Features\n\n- [Meta](#meta)\n    - [Type](#meta-type)\n    - [Key](#public-key)\n    - [Seed](#seed)\n    - [Fingerprint](#fingerprint)\n- [ID](#id)\n    - [Type](#id-type)\n    - [Name](#id-name)\n    - [Address](#id-address)\n    - [Terminal](#terminal)\n- [Samples](#samples)\n\n## Meta\n\nThe **Meta** was generated by your **private key**, it can be used to build a new ID for entity, or verify the ID/PK pair.\n\nIt consists of 4 fields:\n\n| Field       | Description                              |\n| ----------- | ---------------------------------------- |\n| type        | Algorithm Version                        |\n| key         | Public Key                               |\n| seed        | Entity Name (Optional)                   |\n| fingerprint | Signature to generate address (Optional) |\n\nIf ```seed``` exists, ```fingerprint = privateKey.sign(seed)```\n\n### Meta Type\n\n1. ```MKM``` _(Default)_\n2. ```BTC```\n3. ~~Extended BTC~~\n4. ```ETH```\n5. ~~Extended ETH~~\n6. ...\n\n### Public Key\n\nA **public key** (PK) was bound to an ID by the **Meta Algorithm**.\n\n### Seed\n\nA string as same as **ID.name** for generate the fingerprint.\n\n### Fingerprint\n\nTHe **fingerprint** field was generated by your **private key** and **seed**:\n\n````objective-c\ndata = [seed dataUsingEncoding:NSUTF8StringEncoding];\nfingerprint = [privateKey sign:data];\n````\n\n## ID\n\nThe **ID** is used to identify an **entity**(user/group). It consists of 3 fields:\n\n| Field       | Description                    |\n| ----------- | ------------------------------ |\n| type        | Entity type                    |\n| name        | Same with meta.seed (Optional) |\n| address     | Unique Identification          |\n| terminal    | Login point (Optional)         |\n\nThe ID format is ```name@address[/terminal]```.\n\n### ID Type\n\n```objective-c\ntypedef NS_ENUM(UInt8, MKMNetworkID) {\n    \n    /**\n     *  Main: 0, 1\n     */\n    MKMEntityType_User           = 0x00, // 0000 0000\n    MKMEntityType_Group          = 0x01, // 0000 0001 (User Group)\n    \n    /**\n     *  Network: 2, 3\n     */\n    MKMEntityType_Station        = 0x02, // 0000 0010 (Server Node)\n    MKMEntityType_ISP            = 0x03, // 0000 0011 (Service Provider)\n    //MKMEntityType_StationGroup = 0x03, // 0000 0011\n\n    /**\n     *  Bot: 4, 5\n     */\n    MKMEntityType_Bot            = 0x04, // 0000 0100 (Business Node)\n    MKMEntityType_ICP            = 0x05, // 0000 0101 (Content Provider)\n    //MKMEntityType_BotGroup     = 0x05, // 0000 0101\n\n    /**\n     *  Management: 6, 7, 8\n     */\n    //MKMEntityType_Supervisor   = 0x06, // 0000 0110 (Company President)\n    //MKMEntityType_Company      = 0x07, // 0000 0111 (Super Group for ISP/ICP)\n    //MKMEntityType_CA           = 0x08, // 0000 1000 (Certification Authority)\n\n    /*\n     *  Customized: 64, 65\n     */\n    //MKMEntityType_AppUser      = 0x40, // 0100 0000 (Application Customized User)\n    //MKMEntityType_AppGroup     = 0x41, // 0100 0001 (Application Customized Group)\n\n    /**\n     *  Broadcast: 128, 129\n     */\n    MKMEntityType_Any            = 0x80, // 1000 0000 (anyone@anywhere)\n    MKMEntityType_Every          = 0x81, // 1000 0001 (everyone@everywhere)\n};\ntypedef UInt8 MKMEntityType;\n\n#define MKMEntityTypeIsUser(network)      (((network) \u0026 MKMEntityType_Group) == MKMEntityType_User)\n#define MKMEntityTypeIsGroup(network)     (((network) \u0026 MKMEntityType_Group) == MKMEntityType_Group)\n#define MKMEntityTypeIsBroadcast(network) (((network) \u0026 MKMEntityType_Any) == MKMEntityType_Any)\n```\n\n### ID Name\nThe **Name** field is a username, or just a random string for group:\n\n1. The length of name must more than 1 byte, less than 32 bytes;\n2. It should be composed by a-z, A-Z, 0-9, or charactors '_', '-', '.';\n3. It cannot contain key charactors('@', '/').\n\nName examples:\n\n```objective-c\nuser_name  = @\"Albert.Moky\";\ngroup_name = @\"Group-9527\";\n```\n\n### ID Address\n\nThe **Address** field was created with the Meta and a **Network ID**:\n\n#### BTC Address\n\n```objective-c\n#import \u003cMingKeMing/Type.h\u003e\n#import \u003cMingKeMing/MingKeMing.h\u003e\n\nNS_ASSUME_NONNULL_BEGIN\n\n/*\n *  Address like BitCoin\n *\n *      data format: \"network+digest+code\"\n *          network    --  1 byte\n *          digest     -- 20 bytes\n *          code       --  4 bytes\n *\n *      algorithm:\n *          fingerprint = sign(seed, SK);  // public key data\n *          digest      = ripemd160(sha256(fingerprint));\n *          code        = sha256(sha256(network + digest)).prefix(4);\n *          address     = base58_encode(network + digest + code);\n */\n@interface DIMBTCAddress : MKString \u003cMKMAddress\u003e\n\n- (instancetype)initWithString:(NSString *)address type:(MKMEntityType)network\nNS_DESIGNATED_INITIALIZER;\n\n/**\n *  Generate address with fingerprint and network ID\n *\n * @param fingerprint = meta.fingerprint or key.data\n * @param network - address type\n * @return Address object\n */\n+ (instancetype)generate:(NSData *)fingerprint type:(MKMEntityType)network;\n\n/**\n *  Parse a string for BTC address\n *\n * @param string - address string\n * @return null on error\n */\n+ (instancetype)parse:(NSString *)string;\n\n@end\n\nNS_ASSUME_NONNULL_END\n```\n\n```objective-c\n#import \"DIMBTCAddress.h\"\n\n@interface DIMBTCAddress ()\n\n@property (nonatomic) MKMEntityType network; // Network ID\n\n@end\n\n/**\n *  BTC address algorithm:\n *      digest     = ripemd160(sha256(fingerprint));\n *      check_code = sha256(sha256(network + digest)).prefix(4);\n *      addr       = base58_encode(network + digest + check_code);\n */\n@implementation DIMBTCAddress\n\n- (instancetype)init {\n    NSAssert(false, @\"DON'T call me!\");\n    NSString *string = nil;\n    return [self initWithString:string];\n}\n\n- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {\n    NSAssert(false, @\"DON'T call me!\");\n    NSString *string = nil;\n    return [self initWithString:string type:0];\n}\n\n- (instancetype)initWithString:(NSString *)address {\n    //NSAssert(false, @\"DON'T call me!\");\n    return [self initWithString:address type:0];\n}\n\n/* designated initializer */\n- (instancetype)initWithString:(NSString *)address type:(MKMEntityType)network {\n    if (self = [super initWithString:address]) {\n        _network = network;\n    }\n    return self;\n}\n\n- (id)copyWithZone:(nullable NSZone *)zone {\n    DIMBTCAddress *address = [super copyWithZone:zone];\n    if (address) {\n        address.network = _network;\n    }\n    return address;\n}\n\n#pragma mark Coding\n\nstatic inline NSData *check_code(NSData *data) {\n    assert([data length] == 21);\n    NSData *sha256d = MKSHA256Digest(MKSHA256Digest(data));\n    return [sha256d subdataWithRange:NSMakeRange(0, 4)];\n}\n\n+ (instancetype)generate:(NSData *)fingerprint type:(MKMEntityType)network {\n    // 1. digest = ripemd160(sha256(fingerprint))\n    NSData *digest = MKRipeMD160Digest(MKSHA256Digest(fingerprint));\n    // 2. head = network + digest\n    NSMutableData *data = [[NSMutableData alloc] initWithBytes:\u0026network length:1];\n    [data appendData:digest];\n    // 3. cc = sha256(sha256(head)).prefix(4)\n    NSData *cc = check_code(data);\n    // 4. addr = base58_encode(_h + cc)\n    [data appendData:cc];\n    NSString *string = MKBase58Encode(data);\n    return [[self alloc] initWithString:string type:network];\n}\n\n+ (instancetype)parse:(NSString *)string {\n    if (string.length \u003c 26 || string.length \u003e 35) {\n        return nil;\n    }\n    // decode\n    NSData *data = MKBase58Decode(string);\n    if (data.length != 25) {\n        return nil;\n    }\n    // Check Code\n    NSData *prefix = [data subdataWithRange:NSMakeRange(0, 21)];\n    NSData *suffix = [data subdataWithRange:NSMakeRange(21, 4)];\n    NSData *cc = check_code(prefix);\n    if ([cc isEqualToData:suffix]) {\n        UInt8 *bytes = (UInt8 *)data.bytes;\n        return [[self alloc] initWithString:string type:bytes[0]];\n    } else {\n        return nil;\n    }\n}\n\n@end\n```\n\n#### ETH Address\n\n```objective-c\n#import \u003cMingKeMing/Type.h\u003e\n#import \u003cMingKeMing/MingKeMing.h\u003e\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n *  Address like Ethereum\n *\n *      data format: \"0x{address}\"\n *\n *      algorithm:\n *          fingerprint = PK.data;\n *          digest      = keccak256(fingerprint);\n *          address     = hex_encode(digest.suffix(20));\n */\n@interface DIMETHAddress : MKString \u003cMKMAddress\u003e\n\n+ (NSString *)validateAddress:(NSString *)address;\n+ (BOOL)isValidate:(NSString *)address;\n\n/**\n *  Generate ETH address with key.data\n *\n * @param fingerprint = key.data\n * @return Address object\n */\n+ (instancetype)generate:(NSData *)fingerprint;\n\n/**\n *  Parse a string for ETH address\n *\n * @param string - address string\n * @return null on error\n */\n+ (instancetype)parse:(NSString *)string;\n\n@end\n```\n\n```objective-c\n#import \"DIMETHAddress.h\"\n\n// https://eips.ethereum.org/EIPS/eip-55\nstatic inline NSString *eip55(NSString *hex) {\n    NSData *utf8 = MKUTF8Encode(hex);\n    NSData *digest = MKKeccak256Digest(utf8);\n    UInt8 *origin = (UInt8 *)utf8.bytes;\n    UInt8 *hash = (UInt8 *)digest.bytes;\n    UInt8 buffer[40];\n    UInt8 ch;\n    for (int i = 0; i \u003c 40; ++i) {\n        ch = origin[i];\n        if (ch \u003e '9') {\n            // check for each 4 bits in the hash table\n            // if the first bit is '1',\n            //     change the character to uppercase\n            ch -= (hash[i \u003e\u003e 1] \u003c\u003c (i \u003c\u003c 2 \u0026 4) \u0026 0x80) \u003e\u003e 2;\n        }\n        buffer[i] = ch;\n    }\n    return [[NSString alloc] initWithBytes:buffer length:40 encoding:NSUTF8StringEncoding];\n}\n\nstatic inline BOOL is_eth(NSString *address) {\n    if (address.length != 42) {\n        return NO;\n    }\n    NSData *data = MKUTF8Encode(address);\n    UInt8 *buffer = (UInt8 *)data.bytes;\n    if (buffer[0] != '0' || buffer[1]!= 'x') {\n        return NO;\n    }\n    char ch;\n    for (int i = 2; i \u003c 42; ++i) {\n        ch = buffer[i];\n        if (ch \u003e= '0' \u0026\u0026 ch \u003c= '9') {\n            continue;\n        }\n        if (ch \u003e= 'A' \u0026\u0026 ch \u003c= 'Z') {\n            continue;\n        }\n        if (ch \u003e= 'a' \u0026\u0026 ch \u003c= 'z') {\n            continue;\n        }\n        // unexpected character\n        return NO;\n    }\n    return YES;\n}\n\n@implementation DIMETHAddress\n\n// Override\n- (MKMEntityType)network {\n    return MKMEntityType_User;\n}\n\n#pragma mark Coding\n\n+ (NSString *)validateAddress:(NSString *)address {\n    if (is_eth(address)) {\n        address = [address substringFromIndex:2];\n        address = [address lowercaseString];\n        return [NSString stringWithFormat:@\"0x%@\", eip55(address)];\n    }\n    return nil;\n}\n\n+ (BOOL)isValidate:(NSString *)address {\n    NSString *validate = [self validateAddress:address];\n    return [validate isEqualToString:address];\n}\n\n+ (instancetype)generate:(NSData *)fingerprint {\n    if (fingerprint.length == 65) {\n        fingerprint = [fingerprint subdataWithRange:NSMakeRange(1, 64)];\n    }\n    NSAssert(fingerprint.length == 64, @\"key data length error: %lu\", fingerprint.length);\n    // 1. digest = keccak256(fingerprint);\n    NSData *digest = MKKeccak256Digest(fingerprint);\n    // 2. address = hex_encode(digest.suffix(20));\n    NSData *tail = [digest subdataWithRange:NSMakeRange(digest.length - 20, 20)];\n    NSString *hex = MKHexEncode(tail);\n    NSString *address = [NSString stringWithFormat:@\"0x%@\", eip55(hex)];\n    return [[self alloc] initWithString:address];\n}\n\n+ (instancetype)parse:(NSString *)string {\n    if (is_eth(string)) {\n        return [[self alloc] initWithString:string];\n    }\n    return nil;\n}\n\n@end\n```\n\nWhen you get a meta for the entity ID from the network,\nyou must verify it with the consensus algorithm before accepting its **public key**.\n\n### Terminal\n\nA resource identifier as **Login Point**.\n\n## Samples\n\nID examples\n\n```objective-c\nID1 = @\"hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj\";  // Immortal Hulk\nID2 = @\"moki@4WDfe3zZ4T7opFSi3iDAKiuTnUHjxmXekk\";  // Monkey King\n```\n\nMeta Example (JsON) for ```hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj```\n\n```javascript\n{\n    \"type\"        : \"1\",\n    \"key\"         : {\n        \"algorithm\" : \"RSA\",\n        \"data\"      : \"-----BEGIN PUBLIC KEY-----\\nMIGJAoGBALB+vbUK48UU9rjlgnohQowME+3JtTb2hLPqtatVOW364/EKFq0/PSdnZVE9V2Zq+pbX7dj3nCS4pWnYf40ELH8wuDm0Tc4jQ70v4LgAcdy3JGTnWUGiCsY+0Z8kNzRkm3FJid592FL7ryzfvIzB9bjg8U2JqlyCVAyUYEnKv4lDAgMBAAE=\\n-----END PUBLIC KEY-----\",\n        \"mode\"      : \"ECB\",\n        \"padding\"   : \"PKCS1\",\n        \"digest\"    : \"SHA256\"\n    },\n    \"seed\"        : \"hulk\",\n    \"fingerprint\" : \"jIPGWpWSbR/DQH6ol3t9DSFkYroVHQDvtbJErmFztMUP2DgRrRSNWuoKY5Y26qL38wfXJQXjYiWqNWKQmQe/gK8M8NkU7lRwm+2nh9wSBYV6Q4WXsCboKbnM0+HVn9Vdfp21hMMGrxTX1pBPRbi0567ZjNQC8ffdW2WvQSoec2I=\"\n}\n```\n\n(All data encoded with **BASE64** algorithm as default, excepts the **address**)\n\n----\n\nCopyright \u0026copy; 2018-2026 Albert Moky\n[![Followers](https://img.shields.io/github/followers/moky)](https://github.com/moky?tab=followers)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimchat%2Fmkm-objc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdimchat%2Fmkm-objc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimchat%2Fmkm-objc/lists"}