Análise de frequência: analisamos uma das tarefas favoritas dos participantes da etapa on-line do NeoQUEST-2020


Hoje estamos publicando a tarefa Wright-Up NeoQUEST-2020 , sobre a qual nossos participantes escreveram: “4 Task mega cool” e “The best task of the Olympiad”.
Apesar da aparente simplicidade, apenas 8 pessoas concluíram esta tarefa! E agora você pode conhecê-lo melhor, por isso - seja bem-vindo no gato!


Assim, os participantes são convidados a baixar a gravação de áudio . Um minuto de escuta é suficiente para entender que o código Morse nem cheira aqui, assim como palavras significativas na gravação de áudio também não são observadas. Portanto, terminamos a tortura ouvindo e começamos a olhar o som com mais detalhes. Por exemplo, usando o bom e velho Audacity (e gratuito) . Abrimos a gravação de áudio e prestamos atenção à sua estrutura: entre as teclas, há um silêncio absoluto (alguém teve sorte com as condições de trabalho, você não tem telefonemas e bate-papo para sempre!), O que significa que não será difícil extrair cada tecla pressionando as seções de filtragem com amplitude de sinal zero.



Ok, vamos lá. Agora, temos duas coisas: uma "matriz" na qual existem 100.500 cliques e a esperança de que, entre esses sons, haja repetitivos - só então se pode dizer que "a tecla X foi pressionada N vezes e a tecla Y foi M vezes". Assim, todos os dados iniciais foram analisados, resta responder à pergunta “a que tal conjunto de declarações nos levará, desde que a gravação de áudio dure 10 minutos?”. Sim, está certo, é hora de descobrir a análise de frequência clássica . Bem, testamos nossa teoria usando python, numpy e scikits.audiolab (para processar o som, você pode escolher qualquer outro pacote e até mesmo o idioma com o mesmo sucesso).
Para configurar o ambiente, você pode executar os seguintes comandos (ele definitivamente funciona no Ubuntu 19.10):

$ sudo apt-get install -y python python-dev python-pip python-setuptools libsndfile-dev python-numpy
$ pip install --upgrade pip
$ pip install scikits.audiolab


Agora, implementamos o teste de nossa suposição em várias linhas de código que usam a maneira mais primitiva de identificar o som do clique - pela soma dos valores da matriz numpy correspondente:

get list of separated ‘clicks’
data, fs, enc = scikits.audiolab.wavread(filename)
data = data.ravel()
clicks = [list(g) for k, g in groupby(data, lambda x: x != 0) if k]

# calculate number of unique ‘clicks’ and their frequences
freqs = dict() 
cypher_test = list()
for click in clicks:
    value = np.sum(np.array(click), dtype = np.float32)
    cypher_test.append(value)
    if value not in freqs:
        freqs[value] = 1
    else:
        freqs[value] += 1


O resultado da execução do código, mostrado no diagrama - como o calor de uma fogueira no meio de um inverno nuclear - não pode deixar de aquecer a alma: pelo menos 27 cliques únicos, e até a aparência da distribuição inspira confiança de que a análise de frequência não será fútil.



Segundo a Wikipedia e outras fontes mais confiáveis, 26 letras em inglês, classificadas em ordem decrescente de ocorrência, formam a série etaoinshrdlcumwfgypbvkjxqz . Além disso, é claro, uma lacuna, que ocupa uma posição de liderança. Você sabe o que fazer! Novamente, usamos várias linhas de código primitivo para comparar cada som clicando em sua letra (na frequência de ocorrência) e realizamos a substituição inicial:

COMMON_FREQ_ALPHABET = { 0:' ', 1:'e', 2:'t', 3:'a', 4:'o', 5:'i', 6:'n', 7:'s', 8:'h', 9:'r', 10:'d', 11:'l', 12:'c', 13:'u', 14:'m',15:'w', 16:'f', 17:'g', 18:'y', 19:'p', 20:'b', 21:'v', 22:'k', 23:'j', 24:'x', 25:'q', 26:'z' }

# calculate key
key = dict()
index = 0
for freq in sorted(freqs.items(), key=operator.itemgetter(1),reverse=True):
    key[freq[0]] = COMMON_FREQ_ALPHABET[index]
    index +=1

# replace sounds according the key
partly_plain_text = ""
for elem in cypher_test:
	partly_plain_text += key[elem]


Após substituir a análise de frequência, obtemos o seguinte texto:

onlineayvinf saty stw vltn selg kird moaher csctl ncmertl we tnswer utn metscre gtll saory retl enocfh worb ltrfe tvvetr tftin vltue scn satra zero gtua t gew rotd sveuitl vroklem etsa ketcay idet who lef ipere saone retuh vrodcua uca fipe reuord scre aoob jcesaion oca dcrinf vtss dry ahen show low lisa kltub okxeuas low lifha old frow wtauh aowtrd suhool my frow well heta norah mile mcsa resa tdd tmonf yocnf kesa kird beev kird gooa smtll wts bnow oca utme uca vltna some when bnow awo how dripe tftin vca while oaher some ocr letrn satr mincae digger men scrgtues infor retd hetrd lisa rtin utll vora yes whta idet ftme bind new him old deev eta keftn keftn or socah ahe some mtv tkle sonf i metn saory yetr fold mile dtrb eqtmvle world gish tfe geel ahocstnd one mile his ky ahe tkope ahose uhildren rtin gcll gtll tnimtl ury vocnd vltue ahose shora jciub where ahocfh saood fopern sorry i gorfoa i vromised ao lend yoc my uode fea ia grom my fiahck neoscveruoder htnd ahese binf wind utrb new vossikle tdd grom saood lifha down lipe mincae rotd foa satra gire ahocfh ahose some scn aia iaeai aet iaeai aia iaeai aet iaeai aia iaeai aet iaeai aia iaeai aet iaeai aia iaeai aet iaeai aia iaeai aet iaeai ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa ucn shoa shtbe wtpe ltke nibe shtbe wtpe ltke nibe shtbe wtpe ltke nibe shtbe wtpe ltke nibe shtbe wtpe ltke nibe shtbe wtpe htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn mtd dou htn dou gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe yet gipe

Parece um pouco significativo, mas as palavras individuais são definitivamente adivinhadas. Procure seqüencialmente as palavras nas quais é óbvio qual substituição deve ser feita:
  1. moaher -> mãe e tnswer -> resposta, ou seja, a e t devem ser trocados;
  2. larfe → grande e selg → auto, ou seja, feg devem ser trocados;
  3. kird → pássaro, ou seja, k é substituído por be onlinetyving → onlinetyping, isto é, v substitua por p;
  4. meascre → measure e enocgh → suficiente, ou seja, u e c devem ser trocados.

Como resultado dessas manipulações, o texto é dramaticamente transformado, e sua primeira palavra explica a falta de conectividade: a gravação de áudio foi gravada enquanto se praticava tipografia em um simulador de teclado. Ah, o dono da chave claramente não estava se preparando para o apocalipse! ... Podemos ser felizes por ele, provavelmente agora ele está mexendo muito rapidamente, limpando a neve que bloqueou a saída de seu refúgio. Mas o que é isso para nós? Passaremos os olhos pelo texto, talvez ainda haja algo útil.

onlinetyping stay saw plan self bird mother usual numeral we answer can measure fall story real enough worb large appear again place sun start zero fact a few road special problem east beauty idea who leg ipere stone reach product cut gipe record sure toob juestion out during pass dry then show low list blacb obxects low light old grow watch toward school my grow well heat north mile must rest add among young best bird beep bird foot small was bnow out came cut plant some when bnow two how dripe again put while other some our learn star minute differ men surfaces ingor read heard list rain call port yes what idea game bind new him old deep eat began began or south the some map able song i mean story year gold mile darb eqample world fish age feel thousand one mile his by the abope those children rain full fall animal cry pound place those short juicb where though stood gopern sorry i forgot i promised to lend you my code get it from my github neosupercoder hand these bing wind carb new possible add from stood light down lipe minute road got start fire though those some sun tit iteti tea iteti tit iteti tea iteti tit iteti tea iteti tit iteti tea iteti tit iteti tea iteti tit iteti tea iteti cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot cun shot shabe wape labe nibe shabe wape labe nibe shabe wape labe nibe shabe wape labe nibe shabe wape labe nibe shabe wape han mad doc han mad doc han mad doc han mad doc han mad doc han mad doc han mad doc han mad doc han mad doc han doc fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe yea fipe

Parece que tivemos sorte: durante o treinamento, alguém se distraiu e escreveu uma mensagem de recuperação para o amigo, provavelmente em algum mensageiro: desculpe, esqueci-me de prometer emprestar meu código, obtê-lo no meu neosupercoder do github. Ler a correspondência de outra pessoa, é claro, não é bom, mas há uma exceção de cem por cento. Pagamos mais do que o suficiente por essas informações. Vamos ao github e procuramos o repositório por nome de usuário:



Success! Resta apenas ler o único arquivo do repositório "neo-medicina":



Hurra! Agora somos os felizes proprietários da chave!
Adiante - a análise de outras tarefas do NeoQUEST-2020 - não deixaremos nossos leitores se cansarem do auto-isolamento!

All Articles