Điểm:0

Có thể bẻ khóa Trình tạo công thức tuyến tính nếu tôi chỉ biết mô đun của đầu ra không?

lá cờ sz

Chỉnh sửa được đề xuất bởi fgrieu:

Tôi có một trăm số nguyên trong $\{0,1,2,3,4,5\}$ mà tôi nghi ngờ là các giá trị liên tiếp của $\lfloor x_n/2^{16}\rfloor\bmod6$ tính như $x_{n+1}:=a\cdot x_n+b\bmod m$, với $m=2^{31}$, và $(a,b)\in{(214013,2531011),(22695477,1)}$. Làm thế nào để tôi xác nhận giả thuyết đó, tìm $(a,b)$ được sử dụng, và dự đoán những gì tiếp theo trong trình tự?


Câu hỏi về "Việc triển khai thành thạo bằng ngôn ngữ được biên dịch sẽ mất khoảng một giây trên máy tính để bàn hiện đại."

Tôi đã viết một số mã nhưng dự kiến ​​chúng sẽ chạy trong 20 giờ.

Tôi đang cố gắng tìm hạt giống ngẫu nhiên. Đầu tiên, tôi nhập dữ liệu của mình vào một mảng. Vì tôi không biết dữ liệu đầu tiên của mình là số thứ mấy do máy chủ tạo ra, nên tôi cần phải tìm ra nó. Tôi chỉ biết máy chủ ngừng hoạt động vào 2:00 chiều thứ Năm hàng tuần và khởi động lại vào khoảng 2:45-3:45 chiều cùng ngày. Khi máy chủ được bật, ir tạo 3 số cứ sau 45 giây. Dữ liệu tôi có được thu thập vào thứ sáu 1:50 sáng, vì vậy dữ liệu đầu tiên của tôi có thể là số thứ 2400-2640 của LCG.

Lần đầu tiên tôi chạy rand 2399 lần để loại bỏ 2399 số đầu tiên. Tiếp theo, tôi lặp lại 241 lần để tìm dữ liệu đầu tiên của mình là số thứ mấy do máy chủ tạo ra. (sự không chắc chắn của thời gian khởi động lại máy chủ 2:45-3:45 chiều, 240 số mỗi giờ)

phương pháp của tôi là: Nếu bit 16 của x thứ 2400 bằng bit 0 của $y_1$, sau đó tôi kiểm tra bit 16 của x thứ 2401 và bit 0 của $y_2$, và như thế. Nếu không bằng nhau, ngắt vòng lặp rồi bắt đầu vòng lặp khác, so sánh x thứ 2401 với bit 0 của $y_1$.

cách tốt hơn để làm điều đó là gì? Tôi mới bắt đầu học c ++ hai tuần trước, xin hãy tha thứ cho sự thiếu hiểu biết của tôi.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <inttypes.h>

sử dụng không gian tên std;

const int KẾT QUẢ[3][7] = {
    {0,1,0,1,1,1,1},
    {1,0,1,0,0,0,0},
    {0,1,1,0,1,0,0}
};

tĩnh không dấu dài x;

int test_rand(void)
{
    x = 214013*x + 2531011; // hay là 22695477*x+1
    trả về (int)((x >> 16) & 0x7FFF);
};

int onlyx16(void)
{
    x = 214013*x + 2531011; // hay là 22695477*x+1
    trở lại (x >> 16) & 1;
};

void chk_seed(hạt dài không dấu)
{
    int d1[241]{};
    int d2[241]{};
    int d3[241]{};

    x = hạt giống;

    for (int i = 0; i < 2399; i++) {
        test_rand();
    }

    cho (int i = 0; i < 241; i++)
    {
        d1[i] = onlyx16();
        d2[i] = onlyx16();
        d3[i] = onlyx16();
    };

    int đúng = 0;

    cho (int k = 0; k < 236; k++)
    {
        đúng = 0;
        cho (int i = 0; i < 7; i++)
        {
            nếu ((d1[i + k]) == KẾT QUẢ[0][i])
            {
                đúng += 1;
            }
            khác {
                đúng = 0;
                nghỉ;
            };
            nếu ((d2[i + k]) == KẾT QUẢ[1][i])
            {
                đúng += 1;
            }
            khác {
                đúng = 0;
                nghỉ;
            };
            nếu ((d3[i + k]) == KẾT QUẢ[2][i])
            {
                đúng += 1;
            }
            khác {
                đúng = 0;
                nghỉ;
            };
        };
        nếu (đúng == 21)
        {
            printf("hạt giống 0x%d ổn\n", hạt giống);
            printf("dự báo kết quả:\n");
            for (int vòng = 0; vòng < 5; vòng ++)
            {
                printf("vòng %d ", vòng + 1);
                int new_d[3]{};
                cho (int i = 0; i < 3; i++)
                {
                    new_d[i] = test_rand()% 6;
                    printf("%d", new_d[i]);
                };
                printf("\n");
            }
        };
    }
};

int chính ()
{
    for (hạt dài không dấu = 0; hạt < 0x100000000; hạt ++)
        chk_seed(hạt giống);
};

$x_{n+1} = (a \cdot x_{n} + b) \mod m$

Trong tình huống bình thường, $x_{n+1}$$x_n$ được biêt đên. Nhưng bây giờ tôi chỉ biết $x_n\mod 6$$x_{n+1}\mod 6$.

Tôi đã tìm kiếm nhiều trang web trên google nhưng tôi chỉ tìm thấy một câu hỏi nói về vấn đề này.

Dự đoán các giá trị từ Trình tạo đồng dư tuyến tính

Tuy nhiên, nó không rõ ràng lắm và tôi vẫn không biết mình nên làm gì sau khi đọc nó. Tôi hy vọng ai đó có thể cung cấp một số mã toán học hoặc ví dụ để tôi có thể học hỏi từ quá trình thử và sai.

Tôi muốn tìm a, b, m sau đó sử dụng mã nguồn C++ mà tôi tìm thấy ở đây để bắt đầu sử dụng hạt giống.

Tôi đã tìm thấy một câu trả lời ở đây nói về cách tìm m, nhưng tôi không biết $x_{n+1}$$x_n$.

https://security.stackexchange.com/questions/4268/cracking-a-linear-congruential-generator

Tôi chưa quen với chủ đề này, nhưng tôi rất muốn bẻ khóa PRNG này, PRNG này khiến tôi đau khổ rất nhiều, tôi quyết định học lập trình vì PRNG này. Cảm ơn sự giúp đỡ của bạn!

fgrieu avatar
lá cờ ng
Độ khó phụ thuộc vào việc $a$, $b$, $m$ có được đưa ra hay không; trên nếu $m$ là lũy thừa của hai, và cái nào; và xem có bao nhiêu $x_n\bmod 6$. Nếu sự cố được yêu cầu đối với LCG mặc định của Java: bạn thực hiện _not_ get $n\bmod6$ ở đầu ra! Cả `rand` của MSVC và Borland đều không trả về $x_n$.Theo báo cáo, họ trả về các bit 30..16 (tức là 15 bit) của $x_n$, xem [điều này](https://stackoverflow.com/q/6793065/903600) và [điều này](https://stackoverflow.com/ q/14672358/903600). Vì vậy, tôi nghi ngờ về «biết $x_n\bmod6$».
fairytale avatar
lá cờ sz
@fgrieu Tôi biết một trăm $x_n\bmod 6$. Tôi đã kiểm tra các tệp .exe trong thư mục, trình biên dịch của một người là MSVC, trình biên dịch của một người khác là Borland C++, vì vậy tôi đã thử MSVC và Borland rand, tuy nhiên chúng không thể cung cấp cho tôi đầu ra chính xác trong tương lai. Tôi chỉ nhận được 0-5 làm đầu ra, vì vậy tôi nghĩ nguyên nhân là do "%6" https://stackoverflow.com/questions/1202687/how-do-i-get-a-specific-range-of-numbers- from-rand Tôi nghĩ đó là một thông lệ phổ biến để nhận phạm vi số ngẫu nhiên cụ thể. [được chỉnh sửa bởi mod để cô đọng nhiều bình luận]
fgrieu avatar
lá cờ ng
Nhưng bạn không có dấu hiệu nào cho thấy đó là $x_n$ được lấy $\bmod6$, như được viết trong câu hỏi. Nếu đúng như vậy, và nếu $m$ là số chẵn và $a$ là số lẻ, như thông thường, thì các số bạn nhận được sẽ là số lẻ và số chẵn. Câu hỏi bạn muốn hỏi có thể là: «Tôi có một trăm số nguyên trong $\{0,1,2,3,4,5\}$ mà tôi nghi ngờ là các giá trị liên tiếp của $\lfloor x_n/2^{16 }\rfloor\bmod6$ được tính là $x_{n+1}:=a\cdot x_n+b\bmod m$, với $m=2^{31}$ và $(a,b)\in\{ (214013,2531011),(22695477,1)\}$. Làm cách nào để xác thực giả thuyết đó, tìm $(a,b)$ được sử dụng và dự đoán điều gì tiếp theo trong chuỗi?»
fairytale avatar
lá cờ sz
@fgrieu OK, hãy thử phương pháp này. Cảm ơn bạn đã gợi ý. Tôi sẽ [chỉnh sửa] câu hỏi sau và thử phương pháp của bạn, tôi không thể sử dụng máy tính ngay bây giờ. [được chỉnh sửa bởi mod để cô đọng nhiều bình luận]
Fractalice avatar
lá cờ in
Bài báo "Tái tạo các biến số nguyên bị cắt ngắn thỏa mãn các công thức tuyến tính" có thể rất phù hợp.
Điểm:3
lá cờ ng

Mỗi nhận xét sửa đổi câu hỏi ban đầu: OP phỏng đoán rằng 100 chữ số $y_n$ Trong $\{0,1,2,3,4,5\}$ sở hữu của họ có được bằng cách sử dụng biểu thức C(++) tương đương với rand()%6 với rand() sử dụng PRNG (không mã hóa) dựa trên Trình tạo đồng dư tuyến tính, với mã tương đương với

tĩnh không dấu dài x;
int rand(void) {
  x = 214013*x+2531011; // hay là 22695477*x+1
return (int)((x>>16)&0x7FFF);
}

Thông báo rằng $x$ ít nhất là 32 bit, nhưng chỉ có 31 bit bậc thấp mới quan trọng do (x>>16)&0x7FFF và C biểu diễn không dấu dài phép nhân với việc cắt bớt các bit bậc cao không phù hợp với biến.

Trừu tượng hóa các chi tiết lập trình, phỏng đoán là $x$ phát triển mỗi $x_{n+1}:=a\cdot x_n+b\bmod m$ với $m=2^{31}$$(a,b)$ đối với một số hằng số cố định được cho là một trong hai $(214013,2531011)$ hoặc $(22695477,1)$. Và rand() đầu ra bit 30â¦16 của $x$ do đó $y_n:=\lfloor x_n/2^{16}\rfloor\bmod 6$ được trao cho $n=0$ đến $99$ (với hạt giống là một số nguyên chưa biết $x_{-1}$ trong một số phạm vi phi vật chất, vì chỉ $x_{-1}\bmod m$ sẽ quan trọng; và tốt hơn hết là chúng ta nên cố gắng tìm $x_0$ dù sao).

OP hỏi liệu có thể xác nhận hoặc xác nhận phỏng đoán đó không và (nếu đúng) tìm $(a,b)$ được sử dụng và dự đoán những gì tiếp theo trong trình tự.

Đúng, điều đó là có thể, với sự tự tin tuyệt vời. Trạng thái hiệu quả của các PRNG được xem xét có 31 bit, chỉ có hai PRNG được xem xét, chúng có thể sử dụng được cho mục đích mô phỏng, do đó chúng ta có thể tìm thấy trạng thái của chúng và trạng thái nào được sử dụng nhiều hơn một chút $31+1=32$ chút thông tin; và chúng tôi nhận được $100\cdot\log_2(6)\approx258,5$ bit, sẽ cung cấp nhiều xác nhận.

Đơn giản nhất là thử cho cả hai phỏng đoán $(a,b)$, và khám phá các giá trị có thể có của $x_0$. Chúng là duy nhất $2^{31}$, biết $y_0$ cho phép giảm một cách có hệ thống theo hệ số $6$. Mỗi người theo dõi $y_i$ tiếp tục loại bỏ $5$ ứng cử viên ra khỏi $6$. Nếu không có ứng cử viên sống sót qua tất cả các $y_i$, giả thuyết bị bác bỏ. Nếu một trận đấu được tìm thấy, chúng tôi biết đó $(a,b)$ chúng tôi đã sử dụng và có thể tính toán bổ sung $y_i$. Việc triển khai thành thạo bằng ngôn ngữ được biên dịch sẽ mất như một giây trên PC để bàn hiện đại.

Nhưng có lẽ muốn phá vỡ mọi thứ trong thời gian thực với CPU \$0,5 hiện đại chạy từ pin \$0,2 hoặc bị kẹt vào một máy tính lập trình của những năm 1970, hoặc là ENIAC. nhận xét rằng $6$ là số chẵn và số chia là $2^{16}$. Nó theo sau $y_n\bmod 2$ là một chút $16$ của $x_n$. Cũng nhận xét rằng kể từ khi $m$ là một sức mạnh của hai, sự thay đổi của một chút trong $x_n$ không lan truyền đến các bit bậc thấp hơn của $x_{n+1}$. Nếu theo bit 16 của $x_n$ chỉ phụ thuộc vào 17 bit thấp của $x_0$. Chúng tôi biết bit 16 của $x_0$, do đó cần kiểm tra nhiều nhất $2^{16}$ ứng cử viên cho các bit 15â¦0 của $x_0$. Sau đó chúng ta có thể tìm thấy 14 bit khác như trên. Điều đó phân chia và chinh phục cách tiếp cận sẽ cho phép giải quyết các tham số lớn hơn nhiều, ví dụ: Biến đổi x loại uin64_ttrả về x>>33, trên một CPU hiện đại.

Tôi tự hỏi chúng ta có thể làm gì nếu $a$, $b$ và/hoặc $m$ không rõ.


Ghi chú ở trên:

  • Nó sử dụng quy ước thống trị trong khoa học máy tính (và mật mã với một vài ngoại lệ như DES): bit được tính từ 0 (bit bậc thấp), do đó nếu một số nguyên không âm $v$ được biểu diễn ở dạng nhị phân như $k$ chút ít $b_j$, sau đó $v=\sum b_j$ với $0\le j<k$. Trong quy ước big-endian, bit 0 được viết ở bên phải: $6\times7=42$ trong số thập phân là $110\times111=101010$ ở dạng nhị phân.
  • biến máy tính x ít nhất là 32 bit, nhưng chỉ có vấn đề 31 bit thứ tự thấp (0 đến 30) và được sử dụng trong $x_n$, do đó $0\le x_n<m=2^{31}$. đầu ra của rand() ít nhất là 16 bit, nhưng chỉ có 15 bit thứ tự thấp (0 đến 14) và tất cả các bit khác đều bằng 0, do đó $0\le$rand()$\le$RAND_MAX$=2^{15}-1$. Nếu $0\le i<15$ sau đó cắn $j$ đầu ra của rand() phù hợp với bit $j+16$ của x. Nó đi sau bit 0 của $y_n$ phù hợp với bit 16 của $x_n$.

Nhận xét (ngoài chủ đề) về mã hiện tại:

  • Nó cố gắng sử dụng khả năng tăng tốc được thực hiện bởi 6 bằng nhau. Tôi duy trì đây là không phải cần thiết để đạt được thời gian thực hiện tính bằng giây, nếu
    • chúng tôi khám phá các giá trị có thể có của $x_0$, chứ không phải là hạt giống nhiều bước trước đó.
    • chúng tôi sử dụng nó $x_0$ là 31 bit, do đó chúng tôi có thể hạn chế tìm kiếm bên ngoài thành [0, 0x7ffffffff] đó là $2^{31}$ ứng viên $x_0$.
    • chúng tôi sử dụng mà chúng tôi biết $y_0$, do đó mà $x_0=2^{16}\cdot(6\cdot u+ y_0)+v$$0\le u<\lceil2^{15}/6\rceil$$0\le v<2^{16}$, giới hạn trong khoảng $2^{31}/6$ ứng cử viên cho $x_0$.
    • chúng tôi tối ưu hóa bài kiểm tra để kiểm tra ứng viên $x_0$ chống lại $y_1$ trong vòng lặp bên trong trên $v$.
  • Bản chất của không bắt buộc ghi chú tăng tốc 6 chẵn là trước tiên tìm các bit 16â¦0 của $x_0$ phù hợp với các giá trị $y_0$ được thu thập, sau đó là các bit 30–¦17. Mã không làm điều đó! Với tốc độ tăng tốc đó, thời gian thực hiện sẽ giảm xuống còn một phần nghìn giây.
  • Chúng ta cần các giá trị đầy đủ của $y_n$ được thu thập (trong cả tìm kiếm không được tối ưu hóa và phần thứ hai của tìm kiếm được tối ưu hóa), nhưng chúng dường như không có sẵn trong đầu vào, mà tôi đoán là $y_n\bmod2$. Hơn nữa, tôi không hiểu tại sao đó là mảng hai chiều KẾT QUẢ[3][7].
  • Khi nào $x_0$ được tìm thấy, nếu cần tìm hạt giống (hay đúng hơn là bit 30–¦0 của số đó) một số bước đã biết trước đó, điều đó có thể được thực hiện hiệu quả bằng cách quay lại LCG bằng cách sử dụng $x_{n-1}:=a^{-1}\,(x_n-b)\bmod m$ ở đâu $a^{-1}$nghịch đảo mô-đun của $a$ modulo $m$.

Đây là mã làm việc không có tăng tốc tùy chọn (do đó có khả năng hoạt động với mô đun giảm cuối cùng lẻ $r$ câu hỏi có ở đâu 6). Hãy thử nó trực tuyến!

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

#define A 214013 // cho VC; 22695477 cho BC
#define B 2531011 // cho VC; 1 cho trước công nguyên
#define R 6 // mô đun, trong [2, 32768]
// static_assert(A > 0 && A % 8 == 5, "A mod 8 phai la 5");
// static_assert(B > 0 && B % 2 == 1, "B mod 2 phai la 1");
// static_assert(R >= 2 && R <= 32768, "R must be in [2, 32768]");

// quyết định modulo, giảm khi R là lũy thừa của hai
#define M ((uint32_t)(((R-1)&R)!=0 ? 0x8000 : R)<<16)

// Chuỗi yn cho VC (a=214013, b=2531011), n=6, seed=1639326023
// Nếu R là lũy thừa của hai, ceil(16/log2(R))+1 mục là đủ
// Mặt khác, đó là các mục ceil(31/log2(R)), do đó 12 cho R=6.
const int16_t y[] = {
  0,5,3,0,4,3,1,0,4,5,4,4,4,5,5,3,0,2,0,5,4,5,0, // 0, 2,5,1,3,5,5,5,
};

// nghịch đảo mô-đun INVA của A modulo M
#define INVA (IN_A(IN_A(IN_A(IN_A((uint32_t)A))))&(M-1))
#define IN_A(v) (v*(2-v*A))

int main(void) {
  // quyết định bắt đầu từ x0 sao cho khớp với y0
  const uint32_t y0 = y[0], y1 = y[1];
  int32_t x0 = (int32_t)(((M >> 16) - y0) / R * R + y0) << 16 | 0xffff;
  uint32_t tìm thấy = 0;
  printf("trình tạo: ((int)((x = %" PRIu32 " * x + %" PRIu32 ") >> 16) & 0x7fff) %% %u\n",
    (uint32_t)A, (uint32_t)B, (không dấu)R);
  trong khi (x0 >= 0) {
    uint32_t x1 = A * (uint32_t)x0 + B;
    làm {
      // khẳng định( (x0 >> 16) % R == y0);
      // khẳng định( x1 == A * (uint32_t)x0 + B);
      if (((x1 >> 16) & 0x7fff) % R == y1) {
        uint32_t x = x1;
        số nguyên;
        for (n = 2; n < sizeof(y) / sizeof(*y); ++n)
          if ((((x = A * x + B) >> 16) & 0x7fff) % R != y[n])
            goto nxt;
        //đã tìm ra giải pháp
        x = (INVA * ((uint32_t)x0 - B)) & (M - 1);
        printf("x0 co the la %" PRId32 ", that la seed=%" PRIu32
          " modulo 0x%" PRIx32 ", mang lại:\n", x0, x, M);
        // chứng minh luận điểm bằng cách hiển thị đầu ra
        cho (n = 0; n < sizeof(y) / sizeof(*y) + 8; ++n)
          printf(" %d", ((int)((x = A * x + B) >> 16) & 0x7fff) % R);
        printf("\n");
        ++tìm thấy;
      }
    nxt: x1 -= (uint32_t)A;
    } while (((x0--) & 0xffff) != 0);
    x0 -= (int32_t)(R - 1) << 16;
  }
  printf("đã tìm thấy %" PRIu32 " giải pháp%s\n", đã tìm thấy, đã tìm thấy > 1 ? "s" : "");
  trả về 0;
}

// năng suất:
// trình tạo: ((int)((x = 214013 * x + 2531011) >> 16) & 0x7fff) % 6
// x0 có thể là 531633902, tức là seed=1639326023 modulo 0x80000000, mang lại:
// 2 3 4 1 5 1 1 5 4 0 3 2 2 5 5 3 5 5 3 4 0 1 1 4 1 3 3 2 5 4 4
// tìm được 1 lời giải
fairytale avatar
lá cờ sz
Nếu $x_n$ là 32768(1000 0000 0000 0000), bit 16 là 0, nếu $y_n\bmod 2$ cũng là 0, thì $y_n$ này khớp với $x_n$. Sau đó, tôi kiểm tra $x_n$ tiếp theo. Tôi có đúng không? (Tôi cho rằng các bit đang đếm từ trái sang nếu bạn không nói "thấp")
fgrieu avatar
lá cờ ng
@fairytale: uh, không. Xem phần mới "_Chú thích ở trên_", đặc biệt là hai câu cuối.
fairytale avatar
lá cờ sz
Trình tự của tôi là 4,5,0,1,4,3,4,5,1,1,0,2,1,2,3,1,0,2,5,2,0. Thật không may, không tìm thấy... Tôi cũng đã thử 1103515245 và 12345 (glibc rand), nhưng vẫn không tìm thấy. Thở dài. Chương trình này rất cũ, được viết trước năm 2006, nó cũng không liên quan đến mục đích nghiêm túc, vì vậy tôi tin rằng nó không phải là PRNG bảo mật bằng mật mã.Bây giờ tôi đoán tác giả có thể đã sử dụng A, B, M của chính mình hoặc anh ta đã sử dụng Mersenne Twister.
fgrieu avatar
lá cờ ng
@fairytale: câu hỏi như được đặt lại được trả lời ở dạng phủ định. Bạn có tệp thực thi ("_Tôi đã kiểm tra các tệp .exe_"), do đó, vẫn còn quá trình hoạt động của kỹ thuật đảo ngược; hủy biên dịch hoặc/và quan sát chương trình đang chạy trong môi trường có công cụ. Điều đó thậm chí còn lạc đề hơn về tiền điện tử-SE so với lập trình. Nhưng có lẽ trên [reverseengineering-SE](https://reverseengineering.stackexchange.com/)?

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.