21 पॉइंट द्वारा GN⁺ 2025-09-19 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • UUIDv47 डेटाबेस में sortable UUIDv7 स्टोर करते हुए, बाहरी API में UUIDv4 जैसा दिखने वाला मान प्रदान करता है
  • केवल timestamp field को XOR masking करके UUIDv7 की time information को सुरक्षित रखता है, और बाकी random fields को ज्यों का त्यों बनाए रखता है
  • SipHash-2-4 का उपयोग करने वाली 128-bit key से masking करके, key exposure के जोखिम के बिना सुरक्षित रूप से जानकारी की सुरक्षा संभव है
  • encode/decode deterministic और reversible हैं, और randomness बनी रहती है, इसलिए collision risk कम है
  • benchmark results बहुत तेज़ performance और आसान integration method प्रदान करते हैं, और PostgreSQL जैसे डेटाबेस के साथ आसानी से जोड़ा जा सकता है

प्रोजेक्ट का अवलोकन और महत्व

  • UUIDv47 एक open-source C library है, जो डेटाबेस के अंदर sorting और indexing के लिए उपयुक्त UUIDv7 स्टोर करती है, जबकि बाहरी API और सिस्टम में UUIDv4 जैसा दिखने वाला मान expose करती है, ताकि privacy protection और high-performance processing दोनों एक साथ हासिल किए जा सकें
  • अन्य UUID conversion algorithms की तुलना में इसमें reversible mapping, RFC compatibility, key recovery impossible जैसी security, zero-deps, और केवल simple header file include करने वाली संरचना जैसे अलग तरह के मजबूत फायदे हैं

मुख्य विशेषताएँ

  • Header-only C (C89), बिना external dependency के सरल integration संभव
  • UUIDv7 के केवल timestamp field को XOR masking करके time information exposure को रोकता है, और बाकी random fields को बदलता नहीं
  • keyed SipHash-2-4 से masking करके 128-bit key के साथ सुरक्षित information protection संभव
  • encode/decode process deterministic और पूरी तरह reversible है (मूल रूप को बिल्कुल restore किया जा सकता है)
  • डेटाबेस स्टोरेज के लिए (v7) और बाहरी exposure के लिए (v4) UUID के बीच तेज़ mapping support
  • test code और benchmark tools सहित कई उदाहरण उपलब्ध

उपयोग का उद्देश्य और लाभ

  • DB में index locality और paging efficiency को अधिकतम करने के लिए sortable UUIDv7 का उपयोग किया जा सकता है
  • बाहर केवल UUIDv4 जैसा दिखने वाला pattern expose करके timestamp leak और tracking को रोकता है
  • SipHash का उपयोग करके key recovery असंभव, secret key safety सुनिश्चित
  • RFC-compatible version/variant bit handling
  • बहुत तेज़ होने के कारण real-time processing और large-scale generation environments में भी प्रभावी

मुख्य संरचना और आंतरिक कार्यप्रणाली

UUIDv7 Layout

  • ts_ms_be: 48-bit big-endian timestamp
  • ver: high nibble 6th byte (0x7=DB, 0x4=external)
  • rand_a: 12-bit random value
  • var: RFC variant (0b10)
  • rand_b: 62-bit random value

masking और mapping logic (Façade mapping)

  • encoding: ts48 XOR mask48(R), version=4 set
  • decoding: encTS XOR mask48(R), version=7 set
  • random fields में कोई बदलाव नहीं
  • SipHash input के रूप में 10-byte random field का उपयोग
  • XOR masking में key पता हो to तुरंत reverse conversion संभव

सुरक्षा मॉडल

  • लक्ष्य: selective input देने पर भी key exposed न हो
  • implementation: SipHash-2-4 नामक keyed pseudo-random function (PRF) का उपयोग
  • 128-bit key का उपयोग, HKDF आदि के माध्यम से key derivation की सिफारिश
  • key rotation के समय UUID के अंदर स्टोर न करके, अलग छोटे key ID को बनाए रखने की सिफारिश

public API (C)

  • uuidv47_encode_v4facade : v7→v4 conversion
  • uuidv47_decode_v4facade : v4→v7 restore
  • version setting, parsing, formatting से जुड़ी अन्य functions भी उपलब्ध

प्रदर्शन और benchmark

  • SipHash masking (10B) operation में 14ns/op से कम, encode+decode full round trip 33ns/op स्तर (Apple M1 के आधार पर)
  • बड़े पैमाने पर UUID generation·mapping में भी तेज़ processing की गारंटी
  • -O3 -march=native options पर सर्वोत्तम performance

integration और विस्तार

  • API boundary पर encode/decode processing की सिफारिश
  • PostgreSQL integration के लिए C extension लिखें
  • sharding करते समय v4 façade को xxh3, SipHash आदि से hash किया जा सकता है

अन्य

  • अन्य भाषा port: Go(n2p5/uuid47) आदि उपलब्ध
  • अनुशंसित hash: xxHash non-PRF होने के कारण information leak की चिंता, SipHash उपयोग की सिफारिश

लाइसेंस

  • MIT लाइसेंस (Stateless Limited, 2025)

1 टिप्पणियां

 
GN⁺ 2025-09-19
Hacker News की राय
  • नमस्ते, मैं uuidv47 का लेखक हूँ। मूल विचार यह है कि अंदरूनी तौर पर UUIDv7 का उपयोग करके database indexing और sortability बनाए रखें, लेकिन बाहर UUIDv4 जैसा दिखने वाला मान दें ताकि clients के सामने timing pattern उजागर न हों।
    यह 48-bit timestamp को UUID के random field से निकली SipHash-2-4 stream के साथ XOR mask करके काम करता है।
    random bits वैसे ही बने रहते हैं, version अंदर 7 और बाहर 4 में बदल जाता है, और RFC variant value भी बनी रहती है।
    mapping injective है: (ts, rand) → (encTS, rand) संरचना।
    decode encTS ⊕ mask तरीके से होता है, इसलिए पूरी round-trip conversion संभव है।
    security के लिहाज़ से SipHash एक PRF है, इसलिए बाहर से packaged value देखने पर भी key उजागर नहीं होती।
    अगर key गलत हो तो timestamp भी पूरी तरह अलग निकलता है।
    बाहरी key-ID management के साथ key rotation भी support की जा सकती है।
    performance के हिसाब से 10 bytes पर एक SipHash, कुछ 48-bit load/store भर हैं, इसलिए overhead nanosecond स्तर का है; यह C11 header-only है, कोई external dependency नहीं है, और allocation भी नहीं चाहिए।
    testing में SipHash reference vectors, round-trip encode/decode, और version/variant invariance की जाँच की गई है।
    feedback जानना चाहूँगा।

    • यह idea मुझे पसंद आया।
      UUID अक्सर client side पर generate किए जाते हैं, लेकिन इस तरीके में यह संभव नहीं लगता।
      अगर client द्वारा बनाए गए UUID लेकर masked version लौटाया जाए, तो क्या कोई व्यक्ति ऐसे दो UUID नहीं दे सकता जिनमें ts अलग हो लेकिन rand एक जैसा हो, और इससे कमजोरी पैदा हो?
      यानी क्या यह तरीका आखिरकार केवल उसी स्थिति के लिए उपयुक्त है जहाँ UUIDv7 सीधे server side पर generate किया जाए?

    • मेरी दो टिप्पणियाँ हैं।

      1. इससे UUID v7 की उपयोगिता का एक हिस्सा दूसरों के लिए खत्म हो जाता है, इसलिए API उपयोगकर्ता के नज़रिए से यह थोड़ा अफ़सोसजनक है।
      2. अगर external API और internal storage format अलग हों, तो हमेशा इस conversion प्रक्रिया से गुजरना पड़ेगा, जिससे management थोड़ा और जटिल हो जाएगा।
        पता नहीं यह अतिरिक्त झंझट उसकी कीमत के लायक है या नहीं।
    • मेरी सबसे बड़ी चिंता random bits की entropy quality है।
      UUIDv7 collision avoidance पर ज़्यादा केंद्रित है, इसलिए इसकी प्राथमिकता predictability से अधिक collisions से बचना है।
      इसी वजह से RFC में non-randomness के लिए must की बजाय should लिखा गया है, और ऐसी implementations भी हैं जो weak PRNG या counter का उपयोग करती हैं, यहाँ तक कि random bits की जगह अतिरिक्त clock data डाल देती हैं (संदर्भ: RFC9562 s6.2 & s6.9)।
      इसलिए अगर v7 का rand_a, rand_b भरोसे की सीमा के बाहर से आए डेटा हों, तो उन्हें सीधे PRF seed के रूप में इस्तेमाल करना अपेक्षा से अधिक जोखिमभरा हो सकता है।
      PostgreSQL 18 का नया uuidv7() भी high-precision timestamp से rand_a को पूरा भर देता है, और RFC के हिसाब से यह भी ठीक है।
      bulk import में बने UUID देखें तो यह v7-to-v4 तरीका भी अंततः grouping की अनुमति दे सकता है, इसलिए जानकारी लीक हो सकती है।
      engine parts telemetry जैसी चीज़ों में शायद समस्या न हो, लेकिन अगर डेटा सीधे लोगों से जुड़ी पहचान का हो, तो सावधानी ज़रूरी है।
      नतीजतन, जब तक आप खुद भरोसेमंद entropy सुनिश्चित न करें, यह scheme भी timing, serial, या correlation संबंधी जानकारी लीक कर सकती है; इसलिए v7 implementation के source को सीधे जाँचना चाहिए।

    • मुझे यह अच्छा idea नहीं लगता।
      PostgreSQL 18 में optional parameter shift दिए गए अंतराल जितना timestamp को आगे-पीछे कर देता है।
      https://www.postgresql.org/docs/18/functions-uuid.html

  • कुछ साल पहले मैंने अपनी scheme बनाई थी जिसमें DB में sequential numeric ID रखता था और बाहर 4~20 अक्षरों की छोटी random string दिखाता था।
    इसमें मैंने Speck cipher family की एक custom instance का उपयोग किया था, और मुझे यह मज़बूत और काफ़ी अच्छा लगा।
    मैंने इसे पूरा तो कर लिया था, लेकिन जिस project में इस्तेमाल करना था उसे टाल दिया, इसलिए प्रकाशित नहीं किया।
    इस साल या अगले साल मैं उस सामग्री को औपचारिक रूप से जारी करने की योजना बना रहा हूँ।
    implementation, फायदे और नुकसान पर अच्छे notes भी हैं, रुचि हो तो देख सकते हैं।
    https://temp.chrismorgan.info/2025-09-17-tesid/

    • मैंने भी पहले Speck से bigserial PKID को obfuscate करने की कोशिश की थी, लेकिन cross-platform implementations कम थीं, और खासकर pgcrypto में support कमजोर था।
      इसलिए मैंने base58(AES_K1(id{8} || HMAC_K2(id{8})[0..7])) चुना।
      output आमतौर पर लगभग 22 characters का होता है, यानी थोड़ा लंबा है, लेकिन लगभग हर environment में implement किया जा सकता है और performance भी काफ़ी संतोषजनक है।

    • अच्छा idea है।
      मिलते-जुलते concept के रूप में sqids (पहले नाम: hashids) भी देखने लायक है।
      https://sqids.org/

  • पहले मेरा भी कुछ ऐसा ही अनुभव रहा है: मैंने public UUID और API में expose न होने वाला bigint PK, ऐसे दो columns रखकर काम किया था (यह UUIDv7 आने से बहुत पहले की बात है)।
    UUID की convenience थोड़ी कम थी, लेकिन अगर PK को ठीक से अलग रखो तो अलग-अलग DB dumps को आसानी से merge किया जा सकता था, यह बड़ा फ़ायदा था।
    hash-based lookup करने पर भी शायद अंत में दो columns रखने ही पड़ेंगे; हो सकता है मैं hash की कार्यप्रणाली को गलत समझ रहा हूँ।

    • conversion secret cryptographic key से reversible है।
      request में आए uuidv4 value को DB के uuidv7 में बदला जा सकता है।
  • idea दिलचस्प है, लेकिन इच्छा यह है कि database खुद इस तरह की प्रक्रिया को support करे।
    यानी UUIDv7 को “UUIDv4” के साथ परस्पर रूप से convert किया जा सके, और queries में भी दोनों formats को स्पष्ट रूप से अलग करके इस्तेमाल किया जा सके।

  • यह सच में शानदार project है।
    मैंने dchest की siphash library का उपयोग करके इसका Go implementation भी बनाया है।
    https://github.com/n2p5/uuid47
    संदर्भ: https://github.com/dchest/siphash

  • project दिलचस्प है, लेकिन क्या आप कोई वास्तविक उदाहरण दिखा सकते हैं कि uuid v7 में time component उजागर होने का जोखिम कैसे सामने आता है?

    • यदि user behavior pattern या sequence उजागर हो जाए, तो यह समस्याजनक स्थितियाँ पैदा कर सकता है।

      • “पूर्व पति: तुम्हारा dating site userID देखकर तो साफ़ है कि तुमने Tom की party में account बनाया था, है न?”
      • “तुमने कहा था तुम्हारा TZ XYZ है, लेकिन imageID logs (जो creation time के हिसाब से unique हैं) हमेशा सुबह 3 बजे के लगते हैं?”
        individual messages या real-time transactions में शायद फ़र्क न पड़े, लेकिन user account creation या long-term data जैसी चीज़ों में कोई इसका इस्तेमाल पहचान जोड़ने के लिए कर सकता है।
    • मैंने पहले एक CTF में UUID के हिस्से को AES key के रूप में brute force किया था।
      क्योंकि key आंशिक रूप से time source से derive की गई थी, key generation के समय का system time पता चलते ही हमला संभव हो गया।
      एक और सरल उदाहरण: अगर कोई file sharing service सिर्फ website.com/GUID जैसी संरचना प्रकाशित करे और file upload time अलग से न दिखाए,
      तब भी UUIDv7 खुद file upload time का अनुमान लगाने दे सकता है।
      यह ज़रूरी नहीं कि बहुत बड़ा security threat हो, लेकिन यह अनचाहा information disclosure है।

    • उदाहरण के लिए, मान लीजिए कोई system medical data store करता है।
      analysis के लिए MRI scan के तुरंत बाद result upload किया जाता है, और कहा जाता है कि personal information हटा दी जाएगी।
      फिर भी uuidv7 timestamp के आधार पर बाहरी correlation analysis संभव है, जिससे “इस तारीख़ को MRI कराने वाला सिर्फ एक व्यक्ति था, इसलिए यह उसी का MRI होगा” जैसी पहचान निकाली जा सकती है।

  • UUIDv7 की सबसे असुविधाजनक बात यह लगती है कि list में इंसान के लिए उसे आँख से compare (diff) करना बहुत मुश्किल है।
    अगर psql में ऐसा visualization layer हो जिसमें random bits आगे आ जाएँ और actual sort timestamp के आधार पर बना रहे, तो UX में बहुत बड़ा सुधार होगा।

    • मैंने तो बस UUID के आख़िरी हिस्से को देखने की आदत डाल ली है।

    • आप खुद एक function बनाकर query में इस्तेमाल कर सकते हैं।
      उदाहरण के लिए, hex representation के बाद string reverse करना, या reversed base64 में दिखाना—इससे यह छोटा भी लगेगा और अलग-अलग पहचानना भी आसान होगा।

  • यह तरीका काफ़ी ठीक लग रहा है।
    लेकिन timestamp exposure पर बहुत ज़्यादा घबराहट, और sequential ID exposure को सीधे attack surface या business info leak से जोड़ना, मुझे असली security issue से ज़्यादा बेवजह की चिंता लगता है।
    बस समय-समय पर int value में कोई बड़ा random offset जोड़ दीजिए; monotonic बढ़त भी बनी रहेगी और बाहरी observer के लिए pattern पकड़ना मुश्किल होगा।
    आख़िरकार मुझे लगता है कि महत्वपूर्ण जानकारी लीक होने की चिंता के नाम पर थोड़ा ज़्यादा बढ़ा-चढ़ाकर कहा जाता है।

    • यहाँ जो expose हो रहा है वह business information नहीं, client information है।
      system से निकलने वाली जानकारी अपने आप में शायद बहुत मायने न रखे, लेकिन अगर इसे बड़े पैमाने या time series में देखा जाए, तो इससे अतिरिक्त डेटा infer किया जा सकता है।
      उदाहरण के तौर पर, David Kriesel की SpiegelMining talk की तरह, अगर आप सिर्फ़ newspaper article की तारीख़ और author scrape करें, तब भी कौन कब छुट्टी पर गया इसका pattern निकाला जा सकता है।
      कई authors के डेटा की तुलना करते-करते दफ़्तर के romantic relationships तक सामने आ सकते हैं।
  • यह क्यों नहीं कि हर session के लिए अलग cryptographic key हो और बाहर सिर्फ encrypted id ही expose किया जाए?
    तब DB में साधारण sequential id ही पर्याप्त नहीं होगी क्या?

    • token में छिपे timestamp bits को decrypt करने के लिए यह जानना होगा कि कौन-सी key इस्तेमाल हुई थी।
      अगर key को नियमित रूप से बदलें, तो key management बहुत जटिल हो जाएगा, और हर बार सही key कैसे खोजी जाए यह भी समस्या होगी।
  • version 4 की बजाय version 8 क्यों नहीं चुना गया?
    v4 का मतलब random bits होता है, लेकिन वास्तव में यह इतना random नहीं है।
    v8 में bits के अर्थ पर ऐसा प्रतिबंध नहीं है।

    • मुझे भी पक्का जवाब नहीं पता, लेकिन अगर entropy काफ़ी हो तो इसे seed-based PRNG जैसा माना जा सकता है।
      इस तरीके का उद्देश्य ही बाहर से random दिखना है, इसलिए संभव है कि v8 उल्टा ज़्यादा ध्यान खींचता।