Mixed signal

files

main.py

output.txt

Phân tích

Bài này là một trong những bài mà mình thấy nó mô tả 1 tính chất khá là "đặc sản" của Crypto, đó là: "Đi vào thì dễ mà đi ra thì khó :v". Tuy chỉ dùng 1 vòng for và 1 lần if , bài này đã đánh bại kha khá không ít các bạn thí sinh, duy nhất chỉ có đúng 1 bạn giải được 😗

Để hiểu về bài này trước hết mình phải đi qua một khái niệm tưởng như không liên quan mà lại rất cần thiết để giải bài này: Đó chính là hiểu về đa thức trong GF(2).

đa thức trong GF(2)

Bình thường ta hay làm quen với đa thức sẽ có dạng là

a0x0+a1x1+...

với a0,a1,... là các hệ số trong R hay trong C.

 

Tuy nhiên, có 1 loại đa thức hơi đặc biệt một chút, đó là đa thức với các hệ số chỉ có 01, ví dụ như là 1x3+0x2+1x1+0x0 chẳng hạn. Cách cộng và nhân của chúng nó cũng khá là dị với ảo :33

 

Khi mình cộng chúng, thì việc cộng xảy ra như bình thường, giống như chúng ta cộng 2 đa thức với các hệ số là số nguyên vậy,

1x3+0x2+1x1+1x0+0x3+1x2+1x1+0x01x3+1x2+2x1+1x0

tuy nhiên thì sau khi cộng mình sẽ mod 2 tất cả các hệ số đó và rút ra được kết quả 😗

1x3+1x2+2x1+1x0(mod 2)1x3+1x2+0x1+1x0

Tương tự với phép nhân cũng vậy:

1x3+0x2+1x1+1x0×0x3+1x2+1x1+0x0(×0x0)1x4+0x3+1x2+1x1(×1x1)1x5+0x4+1x3+1x2(×1x2)(×0x3)1x5+1x4+1x3+2x2+1x1+0x0(mod 2)1x5+1x4+1x3+0x2+1x1+0x0

 

Điều thú vị là, nếu chúng ta viết đa thức kiểu trên dưới dạng 1 số nhị phân, bằng cách viết các hệ số từ số mũ cao hơn đến thấp hơn, theo thứ tự từ trái sang phải, ví dụ như thế này:

Thì việc chúng ta XORleft shift các số ở vế phải có mối liên hệ mật thiết đến việc nhân và cộng đa thức trong GF(2) đó (ngạc nhiên chưaaa)

 

Cộng 2 đa thức và XOR

Có 1 điều khá là trùng hợp, đó là khi chúng ta XOR 2 số bất kì, thì khi viết quá trình này ở dạng nhị phân, nó giống hệt như là khi mình cộng 2 đa thức trong GF(2) vậy :v

1x3+0x2+1x1+1x01011+0x3+1x2+1x1+0x0vs.01101x3+1x2+0x1+1x01101

Lí do điều này xảy ra là bởi vì XOR nó cho ra output y hệt như là khi chúng ta dùng phép cộng mod 2 vậy.

(nguồn: https://www.youtube.com/watch?v=tNnaEyWxsEI)

Nhân với xn = shift LEFT n bits

Có lẽ cái tên đã nói lên tất cả nhỉ. Khi mình nhân 1 đa thức bất kì với xn với n là số nguyên dương bất kì, thì kết quả giống như khi mình shift 1 số sang trái n bits vậy ~.~

(1x3+0x2+1x1+0x0)x3=1x6+0x5+1x4+0x3+0x2+0x1+0x0vs.1010<<3=1010000

XOR + SHIFT LEFT = f(x)*g(x) trong gf(2)

g(x) là một đa thức trong GF(2), nên nó không chứa các hệ số nào khác ngoài 01, vì vậy có thể viết được dưới dạng xa+xb+.

Điều này dẫn đến việc f(x)g(x) có thể được viết thành như sau:

f(x)g(x)=f(x)xa+f(x)xb+

Trong đó phép nhân với xn có thể được biểu diễn thành việc mình shift 1 số sang trái n bits, còn phép cộng thì được biểu diễn bằng việc mình XOR 2 số.

code tính f(x)*g(x)

Nếu viết g(x) dưới dạng số nhị phân, thì a,b, sẽ tương đương với các vị trí bit trong g = 1. Như vậy, chúng ta có thể suy ra 1 thuật toán mà sẽ tính XOR của tất cả các giá trị f << i khi mà bit thứ i của g = 1. Và từ đó chúng ta có 1 đoạn code như sau:

 

Nếu ta thay g bằng mf bằng m >> (b/2) và xét i chạy từ 0 tới b/2, với m là giá trị của flagb là số bit của m, bùmmm, chúng ta sẽ có challenge này :33

 

Nói cách khác, việc của code challenge này làm là bẻ đôi flag ra làm 2 nửa, coi 2 nửa là 2 đa thức f(x)g(x), và kết quả của hàm mix thực ra là tính f(x)g(x).

Cách giải

Như vậy, để "unmix" cái đống data này chúng ta cần tìm tất cả các divisors của f(x)g(x) và hi vọng f(x) bé nhỏ của chúng ta cũng nằm trong đó. Bằng cách xét những divisors nào của output có các bit của BKSEC{ ở trong đó, chúng ta có thể loại kha khá divisors không liên quan và tìm ra được 1/2 của flag và suy ra được nửa còn lại bằng cách chia f(x)g(x) với f(x).

May thay sage có hàm divisor và có cách để tạo đa thức trong GF(2) dễ ơi là dễ (hoặc các bạn có thể như mình và viết 400 dòng code C++ để giải bài này =v), chúng ta có thể giải bài này trong 1 nốt nhạc 😗

Flag