تولیدکننده اعداد تصادفی چیست؟

تولیدکننده اعداد تصادفی (RNG) سامانه‌ای است که اعداد تصادفی یا شبه‌تصادفی ایجاد می‌کند. اینکه آیا عدد بعدی واقعاً قابل پیش‌بینی است یا خیر، به نوع تولیدکننده بستگی دارد. برخی از تولیدکننده‌ها از فرآیندهای فیزیکی استفاده می‌کنند، برخی اعداد خود را با الگوریتم محاسبه می‌نمایند و برخی از الگوریتم‌ها به گونه‌ای طراحی شده‌اند که حتی کسی که نتایج قبلی را دیده باشد، نمی‌تواند مقدار بعدی را پیش‌بینی کند. تصادفی به نظر رسیدن و غیرقابل پیش‌بینی بودن دو ویژگی کاملاً متفاوت هستند و بخش عمده این مقاله به توضیح همین تفاوت اختصاص دارد.

تولیدکننده‌های سخت‌افزاری اعداد تصادفی

تولیدکننده سخت‌افزاری اعداد تصادفی (HRNG) که تولیدکننده واقعی اعداد تصادفی (TRNG) نیز نامیده می‌شود، اعداد خود را از یک فرآیند فیزیکی استخراج می‌کند. قدیمی‌ترین نمونه‌ها جلوی چشم ما کار می‌کنند: پرتاب سکه، انداختن تاس یا چرخ رولت. قوانین مکانیک هر یک از آن‌ها را کاملاً توصیف می‌کنند، اما یک چرخ رولت استاندارد در عمل همچنان غیرقابل پیش‌بینی است، زیرا تفاوت‌های بسیار جزئی در نحوه شروع چرخش به نتایجی کاملاً متفاوت می‌انجامد.

در مقابل، تولیدکننده‌های سخت‌افزاری مدرن پدیده‌های میکروسکوپی را اندازه‌گیری می‌کنند: نویز شات و نویز حرارتی در مدارهای الکترونیکی، نویز جوی یا اثرات کوانتومی. این موارد منابع مناسبی برای آنتروپی — یعنی غیرقابل پیش‌بینی بودن قابل اندازه‌گیری — هستند؛ اما یک منبع فیزیکی ذاتاً بی‌نقص نیست: ممکن است دچار سوگیری شود، در طول زمان تغییر کند یا دچار خرابی گردد. بنابراین کیفیت آن باید ارزیابی و نظارت شود و در صورت لزوم نتایج آن بیشتر پردازش شوند، همان‌طور که استانداردهایی مانند NIST SP 800-90B توضیح می‌دهند. منابع سخت‌افزاری در جایی استفاده می‌شوند که تضمین امنیت بیشترین اهمیت را دارد — به‌ویژه در رمزنگاری، جایی که ماده اولیه غیرقابل پیش‌بینی برای ساخت کلیدهای پروتکل‌هایی نظیر Transport Layer Security (TLS) را فراهم می‌کنند.

تولیدکننده‌های اعداد شبه‌تصادفی

جایگزین یک دستگاه فیزیکی، استفاده از الگوریتم است. یک تولیدکننده اعداد شبه‌تصادفی (PRNG) دنباله‌ای تولید می‌کند که تصادفی به نظر می‌رسد، اما کاملاً توسط یک مقدار اولیه به نام هسته (seed) تعیین می‌شود. اگر همان هسته را به همان الگوریتم بدهید، هر بار دقیقاً همان دنباله را دریافت خواهید کرد. این ویژگی هر جا که نتیجه باید غیرقابل پیش‌بینی باشد و هسته یا وضعیت داخلی قابل حدس زدن باشد یک نقطه ضعف است، اما هر جا که نتیجه باید تکرارپذیر باشد — مانند یک شبیه‌سازی یا آزمایش که باید دقیقاً بازآفرینی شود — یک مزیت محسوب می‌شود. همچنین PRNGها سریع، کم‌هزینه و برای پیاده‌سازی آسان هستند و به همین دلیل اکثر نرم‌افزارها به آن‌ها متکی هستند. از جمله الگوریتم‌های شناخته‌شده می‌توان به تولیدکننده خطی هم‌نهشتی (LCG)، الگوریتم‌های xorshift و Mersenne Twister اشاره کرد.

Mersenne Twister

الگوریتم Mersenne Twister که در سال 1997 توسط Makoto Matsumoto و Takuji Nishimura معرفی شد، یکی از پرکاربردترین تولیدکننده‌های شبه‌تصادفی و گزینه پیش‌فرض در بسیاری از زبان‌های برنامه‌نویسی است. نام آن از دوره‌اش — یعنی طول دنباله پیش از تکرار — گرفته شده است که در نسخه استاندارد MT19937، عدد اول مرسن 219937 − 1 است. این الگوریتم اکثر آزمون‌های آماری تصادفی بودن را با موفقیت پشت سر می‌گذارد و برای شبیه‌سازی‌ها بسیار مناسب است. با این حال، این الگوریتم برای حفظ اسرار طراحی نشده است: با داشتن 624 مقدار خروجی متوالی 32 بیتی، هر کسی می‌تواند وضعیت داخلی آن را بازسازی کرده و تمامی مقادیر بعدی را پیش‌بینی کند، بنابراین هرگز نباید برای کلیدها، رمزهای عبور یا هر چیزی که باید غیرقابل پیش‌بینی بماند استفاده شود.

تولیدکننده‌های امن از نظر رمزنگاری و آنتروپی

بسیاری از برنامه‌ها به هر دو ویژگی به‌طور همزمان نیاز دارند: سرعت یک الگوریتم و غیرقابل پیش‌بینی بودن یک منبع فیزیکی. راه‌حل این مسئله، یک تولیدکننده اعداد شبه‌تصادفی امن از نظر رمزنگاری (CSPRNG) است. این تولیدکننده همچنان یک نوع PRNG است، اما طوری ساخته شده که دیدن بخشی از نتایج آن هیچ راه عملی برای پیش‌بینی بقیه مقادیر به دست نمی‌دهد، و با یک منبع آنتروپی واقعی تغذیه و به‌طور منظم بازتغذیه می‌شود. هسته‌ای که از یک منبع فیزیکی می‌آید، یک PRNG معمولی را امن نمی‌کند؛ خود الگوریتم باید برای این منظور طراحی شده باشد. یک منبع فیزیکی مانند نویز حرارتی یا زمان‌بندی رویدادهای سخت‌افزاری مقدار کمی تصادفی بودن واقعی فراهم می‌کند و CSPRNG از آن با سرعت بسیار بالاتری دنباله‌ای طولانی از مقادیر می‌سازد. این ترکیب همان چیزی است که سیستم‌عامل در اختیار برنامه‌ها قرار می‌دهد و امروزه در عمل منظور از «تولیدکننده اعداد تصادفی» همین است. با این سازوکار، کلیدهای رمزگذاری، توکن‌های نشست و رمزهای عبور تولید می‌شوند.

اعداد تصادفی در مرورگر

جاوااسکریپت دو روش داخلی برای دریافت مقادیر تصادفی در صفحه وب ارائه می‌دهد که به دسته‌های متفاوتی تعلق دارند. تابع Math.random() یک PRNG معمولی است: استاندارد زبان، الگوریتم آن را به هر مرورگر واگذار کرده و هیچ قولی درباره امنیت نمی‌دهد — برای یک انیمیشن مناسب است، اما برای قرعه‌کشی‌ای که ممکن است کسی به آن اعتراض کند نامناسب است. روش دیگر Web Crypto API است. متد crypto.getRandomValues() مقادیر تصادفی امن از نظر رمزنگاری بازمی‌گرداند که توسط یک CSPRNG مجهز به آنتروپی سیستم‌عامل تولید می‌شوند.

تولیدکننده اعداد تصادفی ما برای هر قرعه‌کشی از Web Crypto API استفاده می‌کند و اعداد به جای سرور، در مرورگر شما تولید می‌شوند. همین منبع سایر ابزارهای این سایت را نیز به کار می‌اندازد، چه بخواهید به ریختن تاس بپردازید، چه شیر یا خط بیندازید یا یک رمز عبور بسازید.

از بیت‌های تصادفی تا عددی در محدوده مورد نظر شما

یک تولیدکننده امن از نظر رمزنگاری تنها نیمی از یک انتخاب عادلانه است. این تولیدکننده بیت‌های خام ارائه می‌دهد و برنامه باید آن‌ها را به عددی در محدوده انتخابی شما تبدیل کند — و اینجاست که سوگیری (bias) می‌تواند وارد شود. فرض کنید منبع مقادیر 0 تا 9 را با شانس برابر تولید می‌کند و شما به عددی از 0 تا 5 نیاز دارید. گرفتن باقیمانده تقسیم بر 6 طبیعی به نظر می‌رسد، اما در این حالت اعداد 0، 1، 2 و 3 هر کدام می‌توانند به دو روش به دست آیند و 4 و 5 تنها به یک روش؛ بنابراین هر یک از اعداد 0 تا 3 شانس 20% دارند و اعداد 4 و 5 هر کدام تنها 10%. یکی از راه‌های رفع این سوگیری این است که مقادیر نامناسب را کنار بگذارید و دوباره عدد تولید کنید؛ مطالب تولیدکننده اعداد تصادفی این موضوع را با جزئیات بررسی می‌کند.

دو نکته دیگر نیز وجود دارد که افراد را شگفت‌زده می‌کند. تکرار اعداد کاملاً طبیعی است: وقتی یک عدد صحیح از 1 تا 10 به‌طور مستقل انتخاب می‌شود و هر عدد شانس برابری دارد، عددی که همین الان انتخاب شده دقیقاً همان شانس 1 در 10 را برای انتخاب مجدد دارد که هر عدد دیگری دارد. یک انتخاب بدون تکرار، نوع متفاوتی از انتخاب است، نه انتخابی تصادفی‌تر. همچنین یک تولیدکننده منصف به تنهایی کل فرآیند را منصفانه نمی‌کند: فهرست شرکت‌کنندگان و تعداد دفعات تلاش نیز به همان اندازه اهمیت دارند، همان‌طور که راهنمای ما درباره اینکه چگونه برنده مسابقه را به صورت تصادفی انتخاب کنیم توضیح می‌دهد.