हम ओरेकल (उर्फ़ सूर्य) java.util.Random
के कार्यान्वयन के बारे में बात कर रहे हैं , फिर हां, एक बार जब आप पर्याप्त बिट्स जानते हैं तो यह संभव है।
Random
48-बिट बीज और एक रैखिक संगत जनरेटर का उपयोग करता है। ये छोटे राज्य के आकार (ब्रूटफोर्सबल!) की वजह से क्रिप्टोग्राफिक रूप से सुरक्षित जेनरेटर नहीं हैं और तथ्य यह है कि आउटपुट सिर्फ यादृच्छिक नहीं है (कई जनरेटर कुछ बिट्स में छोटी चक्र लंबाई प्रदर्शित करेंगे, जिसका अर्थ है कि उन बिट्स को आसानी से भविष्यवाणी भी की जा सकती है अगर अन्य बिट यादृच्छिक लगते हैं)।
nextseed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
यह एक बहुत ही सरल कार्य है, और यह की गणना
seed = ((nextseed - 0xBL) * 0xdfe05bcb1365L) & ((1L << 48) - 1)
द्वारा अगर आप बीज के सभी बिट्स पता उल्टे जा सकता है:
Random
के बीज अद्यतन इस प्रकार है चूंकि 0x5DEECE66DL * 0xdfe05bcb1365L = 1
मोड 2 । इसके साथ, समय के किसी भी बिंदु पर एक एकल बीज मूल्य को सभी पिछले और भविष्य के बीज को पुनर्प्राप्त करने के लिए पर्याप्त है।
Random
में कोई कार्य नहीं है जो पूरे बीज को प्रकट करता है, हालांकि, हमें थोड़ा चालाक होना होगा।
अब, जाहिर है, 48-बिट बीज के साथ, आपको आउटपुट के कम से कम 48 बिट्स का निरीक्षण करना होगा या आपके पास स्पष्ट रूप से इंजेक्शन (और इस तरह उलटा) कार्य नहीं है। हम भाग्य में हैं: nextLong
((long)(next(32)) << 32) + next(32);
देता है, इसलिए यह आउटपुट के 64 बिट (हमें आवश्यकता से अधिक) उत्पन्न करता है। दरअसल, हम शायद nextDouble
(जो 53 बिट्स उत्पन्न करता है) के साथ कर सकते हैं, या किसी भी अन्य फ़ंक्शन की बार-बार कॉल कर सकते हैं। नोट इन कार्यों कर सकते हैं 2 से अधिक उत्पादन नहीं बीज की सीमित आकार की वजह से विशिष्ट मानों कि (इसलिए, उदाहरण के लिए, वहाँ 2 -2 हैं long
कि nextLong
उत्पादन कभी नहीं होगा)।
चलिए विशेष रूप से nextLong
देखें। यह (a << 32) + b
पर एक नंबर देता है जहां a
और b
दोनों 32-बिट मात्राएं हैं। s
nextLong
से पहले बीज बनें। फिर, t = s * 0x5DEECE66DL + 0xBL
दें, ताकि a
t
की उच्च 32 बिट्स हो, और u = t * 0x5DEECE66DL + 0xBL
दें ताकि b
u
की उच्च 32 बिट्स हो। c
और d
क्रमश: t
और u
की निम्न 16 बिट्स बनें।
ध्यान दें कि c
और d
16-बिट मात्राएं हैं, इसलिए हम केवल उन्हें मजबूर कर सकते हैं (क्योंकि हमें केवल एक की आवश्यकता है) और इसके साथ किया जाना चाहिए। यह बहुत सस्ता है, क्योंकि 2 केवल 65536 - कंप्यूटर के लिए छोटा है।लेकिन चलो थोड़ा और चालाक हो और देखें कि क्या कोई तेज तरीका है।
हमारे पास (b << 16) + d = ((a << 16) + c) * 0x5DEECE66DL + 11
है। इस प्रकार, कुछ बीजगणित करते हुए, हम (b << 16) - 11 - (a << 16)*0x5DEECE66DL = c*0x5DEECE66DL - d
, मॉड 2 प्राप्त करते हैं। चूंकि c
और d
दोनों 16-बिट मात्राएं हैं, c*0x5DEECE66DL
में अधिकतम 51 बिट्स हैं। यह उपयोगी मतलब यह है कि
(b << 16) - 11 - (a << 16)*0x5DEECE66DL + (k<<48)
सबसे 6. पर कुछ k
के लिए c*0x5DEECE66DL - d
के बराबर है (वहाँ की गणना करने के c
और d
और अधिक परिष्कृत तरीके हैं, लेकिन क्योंकि k
पर बाध्य इतना छोटा है, यह सिर्फ bruteforce आसान है) ।
हम सिर्फ जब तक हम एक मूल्य कौन शेष आधुनिक 0x5DEECE66DL
नकार दिया गया, 16 बिट (आधुनिक 2 फिर से) है, ताकि हम t
और u
दोनों के निचले 16 बिट की वसूली प्राप्त k
के लिए सभी संभव मूल्यों का परीक्षण कर सकते हैं। उस समय, हमारे पास एक पूर्ण बीज है, इसलिए हम दूसरे समीकरण का उपयोग करके पहले समीकरण, या पिछले बीज का उपयोग कर भविष्य के बीज पा सकते हैं।
import java.util.Random;
public class randhack {
public static long calcSeed(long nextLong) {
final long x = 0x5DEECE66DL;
final long xinv = 0xdfe05bcb1365L;
final long y = 0xBL;
final long mask = ((1L << 48)-1);
long a = nextLong >>> 32;
long b = nextLong & ((1L<<32)-1);
if((b & 0x80000000) != 0)
a++; // b had a sign bit, so we need to restore a
long q = ((b << 16) - y - (a << 16)*x) & mask;
for(long k=0; k<=5; k++) {
long rem = (x - (q + (k<<48))) % x;
long d = (rem + x)%x; // force positive
if(d < 65536) {
long c = ((q + d) * xinv) & mask;
if(c < 65536) {
return ((((a << 16) + c) - y) * xinv) & mask;
}
}
}
throw new RuntimeException("Failed!!");
}
public static void main(String[] args) {
Random r = new Random();
long next = r.nextLong();
System.out.println("Next long value: " + next);
long seed = calcSeed(next);
System.out.println("Seed " + seed);
// setSeed mangles the input, so demangle it here to get the right output
Random r2 = new Random((seed^0x5DEECE66DL) & ((1L << 48)-1));
System.out.println("Next long value from seed: " + r2.nextLong());
}
}
क्या आप मतलब है:
कोड दृष्टिकोण का प्रदर्शन? (आक्रामक नहीं होना चाहिए, लेकिन मुझे यकीन नहीं है कि आप 'रिवर्स-फ़ंक्शन' का अर्थ जानते हैं) –
@OneTwoThree इसके लिए सही नाम उलटा फ़ंक्शन है - मैंने पहले कभी 'रिवर्स' नहीं सुना है। यही कारण है कि @ लुकासकुथ – ddmps
से कुछ भ्रम है, यह यादृच्छिक संख्या के बीज के साथ "हैलो वर्ल्ड" प्रिंटिंग से संबंधित है। http://stackoverflow.com/questions/15182496/why-does-this-code-print-hello-world –