Hoje a gente está com um conteúdo diferente do comum, mas não deixa de ter um aspecto técnico. Eu e um amigo fizemos uma auditoria independente dos Boletins de Urna [BUs] do primeiro turno das Eleições Presidenciais de 2022, disponibilizados pelo TSE. Eu vou falar da técnica que a gente utilizou aqui para conseguir fazer essa conferência e mostrar no final qual foi o resultado dessa análise. Todos os arquivos de código, os dados em Binários e JSON dos boletins e o relatório final vão ficar linkados no final do post, tudo disponível para caso alguém queira utilizar.

Vamos começar do começo…

Esses dias um amigo me mandou algumas imagens [que ficam disponíveis para qualquer pessoa que queira acessar os resultados das eleições no site oficial do Tribunal Superior Eleitoral]. Nesses prints a gente notou que tinha uma diferença entre o número eleitores aptos a votar em determinada seção e, no final, somente para o cargo de Presidente, tinha um total diferente de eleitores aptos a votar. Eu não entendo nada de eleição nem de contagem de votos e não encontrei naquele momento nenhuma informação que justificasse aquela discrepância, e eu fui perguntar pra outro amigo meu, que é advogado e entende muito mais sobre o tema, e ele falou que essa diferença seria o tal do “voto em trânsito”, que acontece quando uma pessoa está fora da zona eleitoral e pede transferência para votar em outro município [N.T.: depois foi adicionada a informação que confirma essa teoria no próprio escopo dos BUs, mas ela não estava disponível no dia que essa análise começou]. A gente ficou com essa parada na cabeça, será que esses votos em trânsito representam muita gente ou tem impacto direto nos resultados, então nós resolvemos verificar essa história.

E é aí que começa a nossa saga, no dia 04/10/2022…

A gente começou a se questionar se seria fácil ou mesmo possível auditar completamente esses boletins, e aí começou a saga. Eu já adianto que auditar os Boletins de Urna é 100% possível, a gente conseguiu fazer essa audição, mas eu vou colocar alguns pontos aqui da dificuldade que foi para fazer isso tudo. A primeira coisa que era descobrir como a gente iria conseguir esses BUs. No site do TSE dava para pesquisar individualmente cada Boletim de Urna, filtrando por estado, por município e, depois, por zona e seção, e você consegue fazer o download desses arquivos, mas isso tem que ser feito um a um. A priori a gente pensou que provavelmente teria algum outro lugar que contivesse todos os BUs, e nós ficamos algumas horas procurando porque, num primeiro momento, a gente não sabia nem quantas urnas eram. Acessando um site do TSE, eu pesquisei pelo termo “API TSE”, para saber se existia alguma API do TSE disponível pra acesso, e eu cheguei ao portal de dados abertos do TSE, que tem vários dados disponibilizados em formato CSV ou Binário, e lá tinha um relatório contendo todas as urnas, todas as seções, as zonas, e tudo mais. A partir desse arquivo, a gente conseguiu chegar numa contabilização, pasmem, de um total de 472.024 urnas. Percebam, é uma quantidade muito grande de urnas, cada uma gera um Boletim de Urna, que é um arquivo Binário, e a gente precisava baixar todos esses BUs, mas a gente não tinha uma forma muito prática para poder fazer isso. Obviamente a gente não ia ficar pegando uma por uma lá no site do TSE.

Eu acabei fazendo um script de crawler [para quem não sabe, web crawler é uma ferramenta, como se fosse um robô, que acessa cada uma das páginas e baixa os arquivos]. Esse robô precisou entrar em 472.024 páginas e fazer o download desses arquivos Binários um a um [o código do crawler também está disponível lá no meu GitHub no link no final deste post]. Esse crawler ficou rodando no meu computador, que tem é uma máquina potente e um link de fibra ótica dedicado, onde eu tive que colocar vários processos simultâneos para conseguir processas isso tudo em pouco mais de 4 dias. Nos cálculos que eu fiz aqui, um computador normal, com uma thread só, demoraria em torno de 17 dias para poder obter esses dados, como eu queria trazer esse conteúdo antes do dia 30 para consegui ter o resultado antes do 2º turno, eu coloquei mais threads para processar.

Pois bem, a gente já tinha conseguido acesso aos dados necessários para fazer essa auditoria, mas essas informações estão em arquivos Binários e ia demandar muito tempo olhar a estrutura do arquivo e descobrir como ele está formatado, então a gente começou a buscar alternativas para fazer uma leitura mais simplificada desses arquivos. Eu percebi que, dentro do próprio site do TSE, quando você entra numa página de resultados, o que de fato ele está acontecendo é que lá tem um JavaScript que pega esse Boletim de Urna em Binário e lê esse arquivo num JSON. Obviamente, isso simplificou muito a vida, eu modifiquei o código do crawler para que, quando ele entrasse em uma página qualquer no site do TSE, também pegasse esse JSON. O programador que fez esse código deixou um console log nesse JSON e, através de uma ferramenta chamada Puppeteer, que é um simulador de navegador, eu consegui fazer o crawler tirar um print screen de cada uma das 472.024 telas, o que gerou arquivos gigantescos. O diretório final gerado pelo crawler tem com alguma coisa em torno de 100GB, entre imagens, JSON e arquivos Binários.

Eu preciso fazer um disclaimer importante aqui, que essa auditoria está sendo feita de maneira independente, sem nenhuma intenção de posicionamento a favor ou contra qualquer um dos candidatos. A intenção é somente analisar se o resultado que os BUs apresentam de fato correspondem ao valor publicado pelo TSE. Também não há como afirmar que os votos registrados nesses BUs são um retrato fiel da realidade, porque o sistema que está rodando dentro da urna é o único responsável por armazenar essas informações em um flashcard, que é como se fosse uma espécie de pendrive, e ele também é responsável por imprimir esses boletins. Numa hipótese de algum tipo de interferência nesse processo, tanto o Boletim de Urna quanto a contabilização que vai para esses arquivos Binários poderiam estar comprometidos. Aqui a gente está auditando a contabilização, ou seja, está pegando todos os boletins, sumarizando eles e vendo se o resultado é igual ao que foi divulgado, mas se o voto está correto, a gente não tem como saber, justamente porque o mesmo hardware que faz a coleta dos dados, também consolida essas informações e gera o Boletim de Urna, assim é impossível afirmar que os dados refletem 100% da realidade. A única forma, no meu ponto de vista, de conseguir auditar de fato a votação, seria se tivesse outro mecanismo, por exemplo, fazendo o log do teclado da urna, aí daria para pegar esses dois logs e bater os dados entre eles para saber se está tudo certo. Como não se tem esses dados, só tem os BUs, a gente está levando em consideração que os Boletins de Urna estão certos. Então a gente só vai verificar se contabilização desses votos está correta e como eles estão divididos.

Continuando…

O próximo passo foi separar as informações do que a gente precisava, porque dentro desse Boletim de Urna tem uma série de dados, como o código da urna, código do flashcard, tem os votos separados por cargo, e a gente só queria o resumo dos votos para Presidente, além de identificar quais as urnas que tiveram voto em trânsito. Dentro do arquivo JSON a gente verificou que a votação é separada como se fossem duas eleições diferentes, uma contendo os votos para deputado federal, para deputado estadual, para senador e governador, e outra com os votos para Presidente, e era justamente aí que tinha uma diferença em algumas urnas, como o número de eleitores aptos da primeira lista com os da segunda lista. A partir dessa informação, a gente separou o que seriam urnas com votos em trânsito para ver se esse número de votos representaria algum tipo de impacto. Depois de uma análise bem profunda dessas informações, a conclusão é que a quantidade de votos em trânsito é ínfima com relação à totalidade. A gente fez um gráfico, por estado, e os que tiveram a maior quantidade de votos em trânsito foram São Paulo, obviamente, Paraná, Santa Catarina, Rio de Janeiro e Minas Gerais, os demais tiveram porcentagens mais ou menos parecidas. O Distrito Federal teve 12 mil votos em trânsito, o que faz muito sentido, porque normalmente as pessoas que moram em Brasília não são de lá. Ainda assim, a contagem aqui de votos em trânsito é muito pequena para justificar algum tipo de impacto. Outro detalhe, a gente tem 51,4% para um candidato e 48,5% para o outro, uma distribuição muito equilibrada, então pode-se dizer que esses votos em trânsito interferiram em praticamente nada no resultado final.

Distribuíção dos votos em trânsito (%)

Um segundo ponto que a gente começou a observar, e aí eu vou dar o contexto de como esse cenário apareceu pra gente lá pelo segundo ou terceiro dia, enquanto a gente estava fazendo o download dos arquivos e contabilizando os relatórios, quando eu tentei importar esses relatórios pra uma planilha no Google Drive, para começar a olhar os números, e uma coisa que me chamou atenção: toda vez que eu tentava subir um CSV dava erro e não conseguia importar tudo. Eu comecei a olhar os arquivos e percebi alguns caracteres esquisitos no meio da contabilização, que sempre apareciam dentro do número serial do flashcard. Depois de separar as urnas que apresentavam esse problema, mais ou menos 10 mil urnas no total, eu coloquei dentro de um diretório todos os BUs correspondentes e comecei a perceber uma espécie de um padrão. Esse código se repetia de acordo com o município, e eu comecei a pensar que poderia ter alguma coisa a mais ali, eram vários trechinhos picotados que tinham certa similaridade a códigos de um arquivo Binário, tinha alguns comandos como DEL, SHA, e tal. Então eu peguei todos esses “erros”, montei um arquivo para ver se fazia algum sentido esse meu pensamento e gerei algo muito parecido a um arquivo Binário. Eu não sou especialista em criptografia nem em arquivos Binários, mas eles tem algumas similaridades, uma desordem, só que contendo alguns metadados. A gente começou a pensar se não poderia ser um código injetado dentro do número do flashcard, o que seria um negócio genial, conseguir pegar um código e picotar ele dentro do Serial FC. Mas, para nossa surpresa, no dia 08/10/2022 [lembre a gente começou a fazer essa analise de fato cerca de 3 dias antes] a gente foi olhar e tinha subido uma atualização no site do TSE, em que o JSON, que antes estava dando problema, começou a trazer o serial correto. Então, o que a gente percebeu é que o parser tinha uma falha na hora de converter o arquivo do Boletim de Urna para JSON, por isso o serial do cartão flash tinha aquele código esquisito, que parecia um código Binário. Para confirmar que não foi feita nenhuma alteração nos números, fizemos uma conferência com os BUs que nós já tínhamos dessas urnas, e não existe nenhuma diferença, então a gente assume que foi um erro no programa, que foi corrigido pela equipe do TSE. Inclusive no relatório eu até coloquei o exemplo de uma urna no Acre, em Marechal Thaumaturgo que, antes, vinha com um código away, e depois dessa correção a página começou a apresentar o serial correto do flashcard. Então, com relação a essa parte de integridade do flashcard, que inicialmente pareceu ter uma anomalia, era só um problema do parser do script do site do TSE, que estava fazendo esse embaralhamento e foi corrigido.

Até então eu falei que nós conseguimos pegar os arquivos binários, mesmo que com certa dificuldade, conseguimos fazer uma análise desses códigos através do parseamento que o site do TSE já faz e retorna num JSON, conseguimos fazer a contabilização, mas qual foi o resultado dessa contabilização? Antes de falar se está tudo ok, eu só vou colocar um último detalhe aqui, que é o seguinte: a auditoria desses arquivos, por mais que sejam arquivos públicos, liberados pelo TSE, que teoricamente qualquer um pode fazer download e analisar, não é um processo fácil nem simples, exige um entendimento técnico bem apurado. A gente precisou fazer um web crawler, o que não é tão simples, a gente precisou uma máquina parruda para processar esses resultados e gerar os relatórios. Então, por mais que seja possível, não é uma auditoria que qualquer um consegue fazer, somente pessoas com conhecimento técnico avançado conseguem fazer e chegar a resultados efetivos. Eu até coloquei uma consideração no relatório falando justamente dessa parte técnica, a meu ver deveria ter formas mais simples de conseguir analisar esses dados, o formato Binário não é um formato muito mercadológico e nem todo mundo consegue mexer nele, não existe uma documentação muito clara, ou pelo menos eu não encontrei, com relação à formatação desse arquivo, então fica difícil de entender. E se não fosse o script do parser do site do TSE, eu não conseguiria ter feito essa análise tão facilmente assim, eu teria que estudar a estrutura binária e procurar alguma ferramenta conseguisse ler esse arquivo. Então só essa ponderação que eu coloco que relação ao nível de dificuldade, não é uma tarefa fácil fazer essa auditoria. Mas é isso aí, vamos para a parte de contabilização para revelar qual foi o resultado dessa auditoria.

Resultados…

Depois de fazer todos os downloads e rodar todos os processos para conseguir analisar esses dados e gerar o resultado final, nós temos o seguinte:

LulaBolsonaroOutrosNulo
TSE*57.259.50451.072.3459.937.8703.487.874
Auditoria57.118.26650.947.4559.864.3993.497.352
Diferença 141.238 (0.2%)124.890 (0.2%)73.471 (0.7%)
*Dados coletados em: https://resultados.tse.jus.br/oficial/app/index.html#/eleicao;e=e544/totalizacao 

Com relação à contagem dos BUs, não há como falar que tem algum tipo de diferença. A diferença foi de 0,2% da contagem, que eu atribuo ao nosso sistema não ter conseguido pegar 100% dos BUs, então existe essa diferença, mas ela é muito pequena. Assim, a conclusão que a gente pode apresentar é que os resultados apresentados pela contagem dos BUs apresentados pelo TSE estão 100% corretos.

Aqui a gente tem os dados sumarizados por estados, com o total de votos pro candidato que ocupou o primeiro lugar [geral], o segundo mais votado [geral], os outros candidatos, e os votos nulos. Todos os resultados são muito próximos aos apresentados pelo TSE.

EstadoCandidato 13Candidato 22OutrosNulo
AC128.848275.30336.29310.418
AL965.410647.468127.64252.579
AM1.019.382879.989146.76437.805
AP196.933187.17247.0407.429
BA5.840.9712.037.750500.186327.035
CE3.570.0691.375.369471.899127.681
DF649.319910.160202.58435.592
ES859.9861.158.475163.57455.448
GO1.446.0731.910.260305.11682.605
MA2.583.363977.762193.298102.758
MG5.783.2965.224.714972.414408.554
MS586.465792.642124.24730.800
MT632.0151.100.037106.05731.169
PA2.437.7391.878.799350.75070.122
PB1.544.243714.247148.58793.341
PE3.535.6001.624.479261.763195.149
PI1.512.486405.871119.11851.878
PR2.351.8403.614.800573.150153.190
RJ3.844.5344.828.333777.844293.141
RN1.257.058619.919119.82856.952
RO261.580580.84260.12414.641
RR68.760207.58722.0224.873
RS2.786.0033.218.666581.896125.610
SC1.270.2672.676.967355.41290.059
SE809.736371.89289.62645.111
SP10.480.06112.226.2202.924.144962.049
TO433.500378.77548.21422.906

A conclusão final dessa auditoria é que é possível auditar por completo os Boletins de Urna, por mais que haja um pouco de dificuldade para obtê-los. A atualização do dia 08/10, disponibilizou esse Boletins de Urna tanto em arquivo Binário quanto em arquivo CSV no site do TSE, mas a gente não tinha essa informação começou [só lembrando, a gente começou a fazer essa auditoria no dia 04/10, e no dia 06/10, se não me engano, foi quando eles disponibilizaram essas informações, então acabamos pegando via web crawler]. Os nossos resultados estão consistentes com relação à contabilização oficial e o relatório final, que está no link no final do post, tem todas essas informações, com todos os arquivos de BUs e arquivos de relatório em CSV, separados por estados. Ainda, concluímos que a contabilização dos votos está 100% correta. Novamente, nós auditamos a contabilização, os Boletins de Urna que são disponibilizados pelo TSE. Isso não quer dizer obrigatoriamente que é 100% fidedigno com relação à votação. A votação a gente não consegue fazer auditoria, porque não existem outros tipos de arquivo que possam se contrapor a esses Boletins de Urna, então a gente tem que considerar que estes estão 100% corretos e, levando isso em consideração, a conclusão é que a contabilização está correta.

Se alguém quiser pegar esses arquivos e olhar mais a fundo, eles estão disponíveis nos links estão abaixo. Espero que vocês tenham gostado do conteúdo, deu muito trabalho para fazer, foram praticamente 5 dias só olhando todos esses aspectos técnicos, tivemos que mexer várias vezes no código porque os relatórios iam crescendo e ficavam impossíveis de ser importados, por exemplo, pro Google Switch, então eu tive que separar esses relatórios por estados, até mesmo para conseguir sumarizar o resultado final, e essa é a conclusão, que estão corretos os dados apresentados pelo TSE como resultado do primeiro turno da Eleição para Presidente da República de 2022. Por hoje é isso, até mais, galera!

Relatório final:

https://drive.google.com/file/d/1lMNPZ38SXg3nDxbnz5tgaPMH601U7JxZ/view

Este relatório foi protocolado na ouvidoria do TSE 09/10/2022 23:44:24, número do protocolo 58262809234424

Arquivos da auditoria:

https://drive.google.com/drive/folders/1lkjI4dCKZrk29o3j0MCGlz26pn6Lw4EW

Arquivos dos scripts de auditoria:

https://github.com/andrehrferreira/auditoria-1turno-eleicao2022

O conteúdo deste post foi retirado do vídeo “Auditei os BUs do TSE, Veja o Resultado!”: