Mehr Unique ID (MUID)

64-bit BigInt database IDs, Base36 case-insensitive identifiers, and 256-bit Base62 account authentication tokens.

Live Account Credentials
Account ID (Base36)
6gq46u
Raw Database ID (BigInt)
13954201234
MUID Secret (Base62 · 256-bit)
1Xy7K9pQ2LmN4zBt8vXw3zR7kM6bC5dA4e3f2g1h0iJ
Account Token (ID : Secret)
6gq46u:1Xy7K9pQ2LmN4zBt8vXw3zR7kM6bC5dA4e3f2g1h0iJ
Tehran: -- UTC: -- Elapsed: -- Random: -- API Regex Valid

MUID Technical Specification

Formal technical architecture, Tehran epoch mathematics, 64-bit BigInt database layout, Base36 identifiers, and 256-bit authentication tokens.

64-Bit Native BigInt K-Sortable Chronological Order Case-Insensitive Base36 256-Bit Cryptographic Secret Zero Sharding Coordination

1. 64-Bit Numeric Database Identifier

Engine Architecture

MUIDs are natively stored as standard 64-bit signed integers (SQL BIGINT). Every identifier combines elapsed seconds from the fixed Tehran epoch with four decimal random sequence digits:

شناسه‌های MUID در پایگاه داده به صورت اعداد صحیح ۶۴ بیتی با علامت (SQL BIGINT) ذخیره می‌شوند. هر شناسه از ترکیب ثانیه‌های سپری‌شده از مبدا تهران و چهار رقم تصادفی تشکیل می‌شود:

RawBigInt = (ElapsedSeconds * 10000) + Random(0..9999)
64-Bit Signed Integer Layout 64 Bits · Up to 9.22 × 1018
0
Elapsed Seconds × 10,000 (~49 Bits)
Rand (14b)
Bit 63: Sign Bit (Always 0, Positive Integer) Bits 62–14: Monotonic Timestamp Range (~29 Million Years) Bits 13–0: 4 Decimal Random Slots (0000–9999)
  • Fixed Epoch: 2026-09-22 00:00:00 (UTC+3:30) = Unix timestamp 1790022600.
  • Throughput Capacity: 10,000 unique sequence slots per second per generator node before collision risk.
  • Official Verification Vectors: 13954201234 ↔ Base36 6eryyky  |  390889398 ↔ Base36 6gq46u
  • مبدا ثابت زمانی: ۲۰۲۶-۰۹-۲۲ ۰۰:۰۰:۰۰ (UTC+3:30) برابر با تایم‌استمپ یونیکس ۱۷۹۰۰۲۲۶۰۰.
  • ظرفیت تولید: ۱۰٬۰۰۰ جایگاه تصادفی در هر ثانیه به ازای هر نود تولیدکننده بدون تداخل.
  • نمونه‌های آزمون رسمی: 13954201234 ↔ در مبنای ۳۶ برابر با 6eryyky  |  390889398 ↔ در مبنای ۳۶ برابر با 6gq46u

2. Public Account ID (Base36)

While databases store the native 64-bit integer, all public-facing APIs, URLs, user interfaces, and customer interactions use Base36:

  • Alphabet: 0123456789abcdefghijklmnopqrstuvwxyz (36 characters).
  • Case-Insensitivity: Normalized via lowercasing. Both 6gq46u and 6GQ46U resolve to the identical raw integer (390889398).
  • URL & Speech Safe: No hyphens, slashes, or special symbols. Safe for email links, phone support, and printed QR codes.
  • Compact Length: Starts at 6 characters and expands to 12 characters over centuries.

در حالی که پایگاه داده عدد ۶۴ بیتی را ذخیره می‌کند، تمام APIهای عمومی، آدرس‌های وب و تعاملات کاربران از Base36 استفاده می‌کنند:

  • الفبا: 0123456789abcdefghijklmnopqrstuvwxyz (۳۶ کاراکتر).
  • عدم حساسیت به حروف کوچک و بزرگ: هر دو شکل 6gq46u و 6GQ46U به یک عدد مشخص (390889398) اشاره دارند.
  • امن برای آدرس وب و تلفن: فاقد خط تیره یا نشانه‌های خاص، مناسب برای خواندن تلفنی، پیامک و لینک‌ها.
  • طول بهینه: با ۶ کاراکتر شروع شده و برای قرن‌ها حداکثر به ۱۲ کاراکتر می‌رسد.

3. 256-Bit Secret & API Regex

Authentication decouples identification from authorization. Each account holds a 256-bit cryptographic secret encoded in Base62:

  • CSPRNG Entropy: 32 secure random bytes (256 bits, equivalent to AES-256).
  • Base62 Encoding: Big-endian conversion (0-9A-Za-z) fixed to exactly 43 characters.
  • Account Token: Formatted as "<account id>:<account secret>".

احراز هویت، شناسه کاربری را از رمز دسترسی جدا می‌کند. هر حساب دارای یک رمز ۲۵۶ بیتی امنیتی بر مبنای Base62 است:

  • آنتروپی امنیتی: ۳۲ بایت تصادفی رمزنگاری‌شده (۲۵۶ بیت، هم‌تراز با استاندارد AES-256).
  • کدگذاری Base62: تبدیل با الفبای 0-9A-Za-z با طول ثابت دقیقاً ۴۳ کاراکتر.
  • توکن حساب: به قالب "<account id>:<account secret>" ساخته می‌شود.
^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$

The Genesis Epoch Decision (Why 2026-09-22?)

Day 0 Offset

The official public launch of the Mehr network was scheduled for 2026-09-23 (corresponding to 2585-07-01, or 1 Mehr 2585 in the Imperial calendar / 1405 SH). The MUID timeline begins exactly one day earlier at 2026-09-22 00:00:00 (UTC+3:30) to anchor the epoch at Day 0 (corresponding to 2585-06-31 / 31 Shahrivar):

تاریخ انتشار رسمی و عمومی شبکه مهر، روز ۲۰۲۶-۰۹-۲۳ برابر با ۲۵۸۵-۰۷-۰۱ (۱ مهر ۲۵۸۵ گاه‌شماری شاهنشاهی / ۱۴۰۵ خورشیدی) تعیین شد. مبدا زمانی MUID دقیقا یک روز قبل در ۲۰۲۶-۰۹-۲۲ ۰۰:۰۰:۰۰ (UTC+3:30) آغاز می‌شود تا تقویم شناسه‌ها بر روی روز صفر (برابر با ۲۵۸۵-۰۶-۳۱ / ۳۱ شهریور) پایه‌گذاری گردد:

Day 0 · Genesis Epoch
2026-09-22 · 2585-06-31 (31 Shahrivar)

The timeline begins at 00:00:00 (UTC+3:30) (Unix timestamp 1790022600). Genesis state, system bootstrapping, and initial node migrations execute cleanly within this 0-indexed day without producing negative offsets.

Day 1 · Official Release
2026-09-23 · 2585-07-01 (1 Mehr)

The official release of Mehr begins. User accounts created on launch day start from Day 1 (after 86,400s), ensuring all public identifiers follow clean positive natural numbers.

4. Database Architecture & Production DDL

Zero Index Fragmentation

Because MUID is time-ordered (K-sortable), B-tree primary key indexes append monotonically at the right leaf edge. This avoids random B-tree page splits, reduces WAL volume, and cuts disk consumption by 50% compared to 128-bit UUIDs.

به دلیل ساختار ترتیبی مبتنی بر زمان (K-sortable)، ایندکس‌های درخت B پایگاه داده به صورت ترتیبی رشد می‌کنند. این امر از شکستن تصادفی صفحات حافظه جلوگیری کرده و مصرف دیسک را در مقایسه با UUIDهای ۱۲۸ بیتی به نصف کاهش می‌دهد.

PostgreSQL
CREATE TABLE accounts (
  id BIGINT PRIMARY KEY,
  secret CHAR(43) NOT NULL,
  created_at TIMESTAMPTZ DEFAULT clock_timestamp()
);
MySQL / MariaDB
CREATE TABLE accounts (
  id BIGINT UNSIGNED PRIMARY KEY,
  secret CHAR(43) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
SQLite
CREATE TABLE accounts (
  id INTEGER PRIMARY KEY,
  secret TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
ClickHouse
CREATE TABLE accounts (
  id UInt64,
  secret FixedString(43),
  created_at DateTime DEFAULT now()
) ENGINE = MergeTree() ORDER BY id;

5. System Comparison Matrix

Standard Evaluation
Identifier System Storage Size Public Representation Case Sensitivity K-Sortable Decoupled Secret Collision Strategy
Mehr Unique ID (MUID) 8 Bytes (BigInt) Base36 (6–12 chars) Insensitive Yes 256-bit Built-in 10,000 slots / sec / node
UUIDv4 (RFC 4122) 16 Bytes Hex Hyphenated (36 chars) Insensitive No (Random) None 122 bits pseudo-random
UUIDv7 (RFC 9562) 16 Bytes Hex Hyphenated (36 chars) Insensitive Yes (ms) None Unix ms + sub-ms random
ULID 16 Bytes Crockford Base32 (26 chars) Insensitive Yes (ms) None 80-bit random per ms
Twitter Snowflake 8 Bytes Decimal String (19 chars) Numeric Yes (ms) None Coordinated Node ID + Seq
NanoID Variable (16–21 B) Custom Base64 (21 chars) Sensitive No (Random) None Uniform distribution

Implementation Examples

Self-contained production implementations in Go, JavaScript, TypeScript, Python, PHP, and POSIX Shell.

muid.go
1package muid2 3import (4	"crypto/rand"5	"fmt"6	"math/big"7	"regexp"8	"strconv"9	"strings"10	"time"11)12 13const (14	EpochTimestamp = 1790022600 // 2026-09-22 00:00:00 UTC+3:30 (Day 0)15	Base62Chars    = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"16)17 18var APITokenRegex = regexp.MustCompile(`^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$`)19 20func Generate() (raw int64, b36 string, err error) {21	elapsed := time.Now().Unix() - EpochTimestamp22	rBig, err := rand.Int(rand.Reader, big.NewInt(10000))23	if err != nil {24		return 0, "", err25	}26	raw = elapsed*10000 + rBig.Int64()27	return raw, strconv.FormatInt(raw, 36), nil28}29 30func Parse(b36 string) (raw int64, createdAt time.Time, randomSuffix int, err error) {31	raw, err = strconv.ParseInt(strings.ToLower(strings.TrimSpace(b36)), 36, 64)32	if err != nil {33		return 0, time.Time{}, 0, err34	}35	return raw, time.Unix(EpochTimestamp+(raw/10000), 0).UTC(), int(raw % 10000), nil36}37 38func GenerateSecret() (string, error) {39	b := make([]byte, 32)40	if _, err := rand.Read(b); err != nil {41		return "", err42	}43	n := new(big.Int).SetBytes(b)44	base := big.NewInt(62)45	rem := new(big.Int)46	var sb strings.Builder47	for n.Sign() > 0 {48		n.DivMod(n, base, rem)49		sb.WriteByte(Base62Chars[rem.Int64()])50	}51	runes := []rune(sb.String())52	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {53		runes[i], runes[j] = runes[j], runes[i]54	}55	res := string(runes)56	for len(res) < 43 {57		res = "0" + res58	}59	return res, nil60}
muid.js
1const EPOCH = 1790022600n; // 2026-09-22 00:00:00 UTC+3:30 (Day 0)2const B62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";3export const API_TOKEN_REGEX = /^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$/;4 5export function generateMuid() {6  const elapsed = BigInt(Math.floor(Date.now() / 1000)) - EPOCH;7  const rand = BigInt(crypto.getRandomValues(new Uint32Array(1))[0] % 10000);8  const raw = elapsed * 10000n + rand;9  return { raw, base36: raw.toString(36) };10}11 12export function parseMuid(b36) {13  const clean = String(b36).trim().toLowerCase();14  let raw = 0n;15  for (const ch of clean) {16    const code = ch.charCodeAt(0);17    raw = raw * 36n + BigInt(code >= 48 && code <= 57 ? code - 48 : code - 87);18  }19  return { raw, base36: raw.toString(36), elapsed: raw / 10000n, rand: Number(raw % 10000n) };20}21 22export function generateSecret() {23  const bytes = crypto.getRandomValues(new Uint8Array(32));24  let num = 0n;25  for (const b of bytes) num = (num << 8n) | BigInt(b);26  let res = "";27  while (num > 0n) {28    res = B62[Number(num % 62n)] + res;29    num /= 62n;30  }31  return res.padStart(43, "0");32}
muid.ts
1export const EPOCH: bigint = 1790022600n; // 2026-09-22 (Day 0)2export const API_TOKEN_REGEX = /^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$/;3const B62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";4 5export function generateMuid(): { raw: bigint; base36: string } {6  const elapsed = BigInt(Math.floor(Date.now() / 1000)) - EPOCH;7  const rand = BigInt(crypto.getRandomValues(new Uint32Array(1))[0] % 10000);8  const raw = elapsed * 10000n + rand;9  return { raw, base36: raw.toString(36) };10}11 12export function parseMuid(b36: string): { raw: bigint; base36: string; elapsed: bigint; rand: number } {13  const clean = b36.trim().toLowerCase();14  let raw = 0n;15  for (const ch of clean) {16    const c = ch.charCodeAt(0);17    raw = raw * 36n + BigInt(c >= 48 && c <= 57 ? c - 48 : c - 87);18  }19  return { raw, base36: raw.toString(36), elapsed: raw / 10000n, rand: Number(raw % 10000n) };20}21 22export function generateSecret(): string {23  const bytes = crypto.getRandomValues(new Uint8Array(32));24  let num = 0n;25  for (const b of bytes) num = (num << 8n) | BigInt(b);26  let res = "";27  while (num > 0n) {28    res = B62[Number(num % 62n)] + res;29    num /= 62n;30  }31  return res.padStart(43, "0");32}
muid.py
1import re, secrets, time2 3EPOCH = 1790022600  # 2026-09-22 00:00:00 UTC+3:30 (Day 0)4B36 = "0123456789abcdefghijklmnopqrstuvwxyz"5B62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"6API_TOKEN_REGEX = re.compile(r"^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$")7 8def encode_base36(n: int) -> str:9    res = []10    while n > 0:11        n, r = divmod(n, 36)12        res.append(B36[r])13    return "".join(reversed(res)) or "0"14 15def generate_muid() -> tuple[int, str]:16    elapsed = int(time.time()) - EPOCH17    raw = elapsed * 10000 + secrets.randbelow(10000)18    return raw, encode_base36(raw)19 20def parse_muid(b36: str) -> dict:21    raw = int(b36.strip(), 36)22    return {"raw": raw, "base36": encode_base36(raw), "elapsed": raw // 10000, "rand": raw % 10000}23 24def generate_secret() -> str:25    n = int.from_bytes(secrets.token_bytes(32), "big")26    res = []27    while n > 0:28        n, r = divmod(n, 62)29        res.append(B62[r])30    return "".join(reversed(res)).zfill(43)
muid.php
1<?php2const EPOCH = 1790022600; // 2026-09-22 00:00:00 UTC+3:30 (Day 0)3const B62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";4const API_TOKEN_REGEX = '/^[0-9a-z]{6,12}:[0-9a-zA-Z]{43}$/';5 6function generateMuid(): array {7    $raw = (time() - EPOCH) * 10000 + random_int(0, 9999);8    return ['raw' => $raw, 'base36' => base_convert((string)$raw, 10, 36)];9}10 11function parseMuid(string $b36): array {12    $raw = (int)base_convert(strtolower(trim($b36)), 36, 10);13    return ['raw' => $raw, 'base36' => strtolower(trim($b36)), 'elapsed' => intdiv($raw, 10000), 'rand' => $raw % 10000];14}15 16function generateSecret(): string {17    $bytes = array_values(unpack("C*", random_bytes(32)));18    $res = "";19    while (true) {20        $zero = true; $rem = 0;21        for ($i = 0; $i < 32; $i++) {22            $cur = $rem * 256 + $bytes[$i];23            $bytes[$i] = intdiv($cur, 62);24            $rem = $cur % 62;25            if ($bytes[$i] !== 0) $zero = false;26        }27        $res = B62[$rem] . $res;28        if ($zero) break;29    }30    return str_pad($res, 43, '0', STR_PAD_LEFT);31}
muid.sh
1#!/bin/sh2# MUID & Secret generator in pure POSIX sh3EPOCH=1790022600 # 2026-09-22 00:00:00 UTC+3:30 (Day 0)4B36="0123456789abcdefghijklmnopqrstuvwxyz"5B62="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"6 7generate_muid() {8    now=$(date +%s)9    rand=$(od -An -N2 -tu2 /dev/urandom | tr -d " \t\n")10    rand=$(( rand % 10000 ))11    raw=$(( (now - EPOCH) * 10000 + rand ))12 13    # Convert 64-bit integer to Base3614    printf "%s %s\n" "$raw" "$B36" | awk "{15        n = \$1; b36 = \$2; res = \"\"16        while (n > 0) {17            rem = n % 3618            res = substr(b36, rem + 1, 1) res19            n = int(n / 36)20        }21        printf \"%s\", res22    }"23}24 25generate_secret() {26    # 32 CSPRNG bytes to 43 Base62 characters27    od -An -v -tu1 -N32 /dev/urandom | awk -v b62="$B62" "{28        for (i = 1; i <= NF; i++) bytes[n++] = \$i29    }30    END {31        res = \"\"32        while (1) {33            all_zero = 1; rem = 034            for (i = 0; i < 32; i++) {35                cur = rem * 256 + bytes[i]36                bytes[i] = int(cur / 62)37                rem = cur % 6238                if (bytes[i] != 0) all_zero = 039            }40            res = substr(b62, rem + 1, 1) res41            if (all_zero) break42        }43        while (length(res) < 43) res = \"0\" res44        printf \"%s\", res45    }"46}47 48printf "%s:%s\n" "$(generate_muid)" "$(generate_secret)"
Copied!