اسپورٹس

گیمز

عام

حسب ضرورت گیمز - پروویبلی فیئر

حسب ضرورت گیمز میں اسے کیسے استعمال کیا جاتا ہے

YEET Originals میں ہر شرط ایک راؤنڈ سیڈ سے شروع ہوتی ہے۔ راؤنڈ سیڈ آپ کے کلائنٹ سیڈ اور شرط کے نونس (nonce) کا HMAC-SHA256 ہوتا ہے، جسے YEET کے منتخب کردہ سرور سیڈ کے ساتھ جوڑا جاتا ہے۔ گیم پھر اس شرط کے لیے درکار ہر رینڈم ویلیو اسی راؤنڈ سیڈ سے حاصل کرتی ہے۔ سرور سیڈ آپ کو کھیلنے سے پہلے ہیش شدہ شکل میں دکھایا جاتا ہے اور جب آپ اپنا سیڈ پیئر تبدیل کرتے ہیں تو ظاہر کر دیا جاتا ہے، تاکہ آپ کسی بھی پرانی شرط کا راؤنڈ سیڈ دوبارہ کیلکولیٹ کر سکیں اور تصدیق کر سکیں کہ شرط لگانے کے بعد اس کا نتیجہ تبدیل نہیں ہوا تھا۔

دیگر تصدیق کنندگان مماثل نہیں ہو سکتے

دوسرے کیسینو کے لیے بنائی گئی ویریفیکیشن سائٹس رینڈم نمبرز مختلف طریقے سے جنریٹ کر سکتی ہیں، اس لیے وہاں YEET کی شرط چیک کرنے سے نتیجہ مختلف آ سکتا ہے۔ YEET کی شرطوں کی تصدیق گیم کی فیئرنس ونڈو کے ویریفائی ٹیب میں، یا اس صفحہ پر موجود کوڈ کے ساتھ کریں۔

بے ترتیب نمبر کی تیاری

ہر شرط دو مراحل میں جنریٹ ہوتی ہے۔ پہلے، آپ کا سیڈ پیئر اور شرط کا نونس (nonce) ایک راؤنڈ سیڈ دیتے ہیں۔ دوسرا، راؤنڈ سیڈ رینڈم بائٹس کا ایک سلسلہ تیار کرتا ہے، اور گیم اس سلسلے سے غیر جانبدار مکمل نمبر پڑھتی ہے۔ ایک جیسے ان پٹ ہمیشہ ایک جیسے نمبر دیتے ہیں، اور یہی چیز نتیجے کو قابلِ تصدیق بناتی ہے۔

1. ان پٹس

  • ہمارے سرور کی طرف سے تیار کردہ بے ترتیب 64-حرفی ہیکسا ڈیسیمل اسٹرنگ
  • ایک اسٹرنگ جس میں آپ کسی بھی وقت تدوین کر سکتے ہیں
  • ایک کاؤنٹر جو ہر کھیلی گئی گیم کے ساتھ بڑھتا رہتا ہے
  • کرسر — راؤنڈ سیڈ میسج کا آخری حصہ۔ یہ ہمیشہ 0 ہوتا ہے۔

2. راؤنڈ سیڈ

راؤنڈ سیڈ سرور سیڈ (32 بائٹس کے طور پر) کے ساتھ clientSeed:nonce:0 ٹیکسٹ پر HMAC-SHA256 ہوتا ہے۔ نتیجہ 32 بائٹس کا ہوتا ہے، جسے 64 ہیکس کیریکٹرز کے طور پر لکھا جاتا ہے۔ ایک شرط کا صرف ایک راؤنڈ سیڈ ہوتا ہے۔

async function deriveGameSeed(serverSeed, clientSeed, nonce) {
  const seedBytes = hexToBytes(serverSeed);
  if (seedBytes.length !== 32) {
    throw new Error(`Server seed must be 32 bytes (64 hex characters), got ${seedBytes.length}.`);
  }

  const key = await crypto.subtle.importKey(
    'raw', toArrayBuffer(seedBytes), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'],
  );
  const message = new TextEncoder().encode(`${clientSeed}:${nonce}:0`);
  return bytesToHex(new Uint8Array(await crypto.subtle.sign('HMAC', key, message)));
}

3. راؤنڈ سیڈ سے اینٹروپی

راؤنڈ سیڈ دوسرے HMAC-SHA256 کی کلید ہے۔ ہر کال ایک 8-بائٹ کاؤنٹر (little-endian، 0 سے شروع ہونے والا) سائن کرتی ہے اور 32 بائٹس کا ایک بلاک دیتی ہے؛ کاؤنٹر فی بلاک ایک کے حساب سے بڑھتا ہے۔ ریڈز موجودہ بلاک سے ترتیب وار بائٹس لیتی ہیں۔ جب کسی ریڈ کو بلاک میں باقی بائٹس سے زیادہ کی ضرورت ہوتی ہے، تو بلاک کے باقی حصے کو چھوڑ دیا جاتا ہے اور اگلا بلاک جنریٹ کیا جاتا ہے۔

class GameEntropy {
  constructor(seedBytes) {
    if (seedBytes.length !== 32) throw new Error('Seed must be exactly 32 bytes (64 hex characters).');
    this.buffer = new Uint8Array(32);
    this.offset = 32;
    this.cursor = 0;
    this.key = crypto.subtle.importKey(
      'raw', toArrayBuffer(seedBytes), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'],
    );
  }

  async next(count) {
    if (count < 1 || count > 32) throw new RangeError('count must be between 1 and 32');

    if (this.offset + count > 32) {
      const message = new ArrayBuffer(8);
      const view = new DataView(message);
      view.setUint32(0, this.cursor >>> 0, true);
      view.setUint32(4, Math.floor(this.cursor / 0x100000000) >>> 0, true);

      const hash = await crypto.subtle.sign('HMAC', await this.key, message);
      this.buffer.set(new Uint8Array(hash));
      this.cursor++;
      this.offset = 0;
    }

    const slice = this.buffer.slice(this.offset, this.offset + count);
    this.offset += count;
    return slice;
  }
}

4. غیر جانبدار نمبرز

نتائج پورے نمبروں کے طور پر اخذ کیے جاتے ہیں۔ readUint32 4 بائٹس کو ایک غیر دستخط شدہ 32 بٹ انٹیجر (لٹل انڈین) کے طور پر پڑھتا ہے۔ unbiasedUint(entropy, n) 0 سے n − 1 تک کا ایک نمبر لوٹاتا ہے، جس میں ہر ایک کے منتخب ہونے کا امکان برابر ہوتا ہے۔ جب n دو کی طاقت (power of two) ہو تو یہ براہ راست باقی ماندہ حصہ لیتا ہے۔ دوسری صورت میں، یہ صرف ان اقدار کو قبول کرتا ہے جو 32 بٹس میں فٹ ہونے والے n کے سب سے بڑے ملٹیپل سے کم ہوں، اور اگر کوئی قدر اس کے برابر یا زیادہ ہو تو یہ دوبارہ پڑھتا ہے، تاکہ کسی نتیجے کو ترجیح نہ ملے۔

async function readUint32(entropy) {
  const bytes = await entropy.next(4);
  return new DataView(bytes.buffer, bytes.byteOffset, 4).getUint32(0, true);
}

async function unbiasedUint(entropy, range) {
  if (range <= 0) throw new Error('Range must be positive');
  if (range === 1) return 0;

  if ((range & (range - 1)) === 0) {
    return (await readUint32(entropy)) % range;
  }

  const maxValue = 0xffffffff;
  const threshold = maxValue - (maxValue % range) - 1;

  for (;;) {
    const raw = await readUint32(entropy);
    if (raw <= threshold) return raw % range;
  }
}

5. ہیلپرز

function hexToBytes(hex) {
  if (typeof hex !== 'string') throw new TypeError('Hex value must be a string.');
  const clean = hex.trim().replace(/^0x/i, '');
  if (clean.length % 2 !== 0) throw new Error('Hex value must have an even length.');
  if (!/^[0-9a-fA-F]*$/.test(clean)) throw new Error('Hex value contains non-hex characters.');

  const bytes = new Uint8Array(clean.length / 2);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = parseInt(clean.substring(i * 2, i * 2 + 2), 16);
  }
  return bytes;
}

function bytesToHex(bytes) {
  return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
}

function toArrayBuffer(bytes) {
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
}

6. شرط کی تصدیق

  • اپنی ہسٹری سے بیٹ کھولیں اور کلائنٹ سیڈ، نونس (nonce) اور ہیش شدہ سرور سیڈ کو کاپی کریں۔
  • سرور سیڈ کو ظاہر کرنے کے لیے اپنے سیڈ جوڑے کو تبدیل کریں، اور چیک کریں کہ آیا اس کا SHA-256 ہیش اس ہیش سے میل کھاتا ہے جو آپ نے بیٹ لگانے سے پہلے دیکھا تھا۔
  • راؤنڈ سیڈ حاصل کرنے کے لیے سرور سیڈ، کلائنٹ سیڈ اور نونس کے ساتھ deriveGameSeed چلائیں۔
  • راؤنڈ سیڈ سے GameEntropy بنائیں، گیم کا کنورژن (کنورژنز دیکھیں) لاگو کریں اور نتیجے کا اپنی بیٹ سے موازنہ کریں۔