We have an innovative seesaw!

問題

ソースコードとoutput.txtが配布されます。
flagをビット列に変換したものとランダムなビット列を用意し、flagの各ビットに対して1/2の確率でランダムビット列とのANDを取ったものに書き換えているらしい。
その試行の16回分の出力がoutput.txtに入ってます。

from Crypto.Util.number import *
from random import random, getrandbits
from flag import flag

flag = bytes_to_long(flag.encode("utf-8"))
length = flag.bit_length()
key = getrandbits(length)
while not length == key.bit_length():
    key = getrandbits(length)

flag = list(bin(flag)[2:])
key = list(bin(key)[2:])

cipher_L = []

for _ in range(16):
    cipher = flag[:]
    m = 0.5

    for i in range(length):
        n = random()
        if n > m:
            cipher[i] = str(eval(cipher[i] + "&" + key[i]))

    cipher_L.append("".join(cipher))

print("cipher =", cipher_L)

解説

ビット同士でANDを取るとき、1が0になることはあれど0が1になることはありません。
つまり0は16回試行しようがその全てで0となっているはず。
逆に1は1になったり0になったりしてますが16回も試行すりゃ1回くらい1になってるはず。
つまり出力の全パターンに対してORを取ればflagが復元できるはず。

inp=[]
ans=0
with open("output_.txt") as f:
    l = [s.strip() for s in f.readlines()]
for i in l:
    ans=ans|(int("0b"+i,0))
print(bin(ans))

(output.txtはリスト形式での出力だったのを1行ずつに書き換えたoutput_.txtを入力に用いています)

これでビット列が復元できたわけですがutf-8へのデコードはまだです。
Pythonでのデコードわかんないよ~~!!とプログラミング能力の低さを露呈させていたところ↓のサイトを見つけて事なきを得ました。
https://dencode.com/ja/
みんなはプログラミングができるようになろうね!

ctf4b{Sh3_54w_4_SEESAW,_5h3_54id_50}