Como funciona um sorteio — um exemplo prático

Percorra um sorteio real do início ao fim: 1.000 comentários elegíveis, 3 vencedores, 9 reservas. Sem jargão, sem omissões.

O cenário

Imagine que o concurso terminou. Os comentários foram obtidos, os filtros do concurso foram aplicados e 1.000 participações são elegíveis. O prémio atribui 3 vencedores com 9 reservas, caso algum dos vencedores não possa ser contactado. Aqui está a probabilidade por participação — idêntica para cada um dos 1.000 comentários elegíveis, independentemente de quando foi publicado ou do comprimento do nome do participante.

Resultado Probabilidade para qualquer participação
Sorteado como vencedor principal (posições 1–3) 3 em 1.000 — 0,30%
Sorteado como reserva (posições 4–12) 9 em 1.000 — 0,90%
Sorteado para qualquer lugar vencedor 12 em 1.000 — 1,20%

Nada disto muda se o concurso tiver 444 comentários ou 444.444. O algoritmo é idêntico. Apenas o denominador varia.

Passo 1 — Recolher e filtrar as participações

A aplicação obtém todos os comentários da publicação do Facebook ou Instagram que ligou e aplica os filtros do concurso — duplicados, palavras bloqueadas, regras de antiguidade de conta, tudo o que foi configurado. O que sobrevive é o conjunto elegível. No nosso cenário são 1.000 comentários. Cada um tem uma linha na base de dados com um ID numérico único; esses 1.000 IDs são a base de todo o sorteio.

Passo 2 — Ordenar numa ordem canónica

Antes de qualquer aleatorização, a aplicação ordena os 1.000 IDs em ordem numérica crescente estrita — 17, 142, 203, 1058, 9941, … — e descarta a ordem em que chegaram. Porquê? Porque o Facebook pode devolver comentários em ordens diferentes consoante a paginação, hora do dia ou alterações no servidor. Se o sorteio utilizasse a ordem do Facebook, dois re-sorteios poderiam produzir vencedores diferentes a partir da mesma semente aleatória. Ordenar primeiro fixa a entrada numa lista canónica, de modo que a semente determina exclusivamente o resultado.

Passo 3 — Bloquear a lista de entrada com um hash SHA-256

A lista ordenada é processada pelo SHA-256 — uma função de hash criptográfico — produzindo uma impressão digital de 64 caracteres. A impressão digital, juntamente com a lista completa, é guardada no registo do concurso. A partir deste momento, qualquer pessoa que inspecione o concurso pode confirmar que a lista elegível não foi alterada: recalcule o hash da lista publicada, compare com a impressão digital guardada, e um único ID alterado produz um hash completamente diferente. Não existe forma de adicionar ou remover silenciosamente um comentário após este passo sem que fique visível.

Passo 4 — Gerar uma semente aleatória de 256 bits

A aplicação solicita à fonte de aleatoriedade criptográfica do sistema operativo (SecureRandom.hex(32)) 32 bytes de aleatoriedade imprevisível e armazena o resultado como uma cadeia hexadecimal de 64 caracteres — por exemplo a3f1…ce. 256 bits significa 2²⁵⁶ ≈ 10⁷⁷ sementes possíveis. Para contexto, o universo observável contém cerca de 10⁸⁰ átomos. Ninguém — nem o criador do concurso, nem o operador, nem um atacante externo — consegue prever ou adivinhar esta semente antes de ser gerada.

Passo 5 — Baralhar os 1.000 IDs e retirar os primeiros 12

A semente inicializa um motor de baralhamento determinístico, que executa um baralhamento de Fisher–Yates sobre os 1.000 IDs ordenados. Fisher–Yates é o algoritmo de baralhamento justo padrão — cada uma das 1.000 participações tem igual probabilidade de acabar em qualquer posição. Após o baralhamento, a aplicação retira as primeiras 12 participações do topo. Este é o passo de seleção na íntegra: baralhamento, corte em 12.

Passo 6 — Atribuir posições

As 12 participações selecionadas são percorridas em ordem. As três primeiras tornam-se vencedores 1, 2 e 3, e as nove seguintes tornam-se reservas 1 a 9. As restantes 988 participações elegíveis são registadas como não selecionadas. Os comentários filtrados anteriormente são marcados como desqualificados com o motivo específico pelo qual não eram elegíveis.

Passo 7 — Publicar tudo

Por fim, a aplicação guarda cinco elementos de evidência no registo do concurso — todos acessíveis publicamente. Sem eles, o resultado seria uma caixa negra. Com eles, qualquer pessoa pode reproduzir o sorteio completo em casa e confirmar que os vencedores publicados são os únicos vencedores que a semente poderia ter produzido.

O que é publicado em cada sorteio

Cada um destes elementos é armazenado no concurso e exposto através das páginas públicas de verificação. Em conjunto tornam o sorteio totalmente reproduzível — mesmas entradas, mesmas saídas, sempre.

  • A semente aleatória de 256 bits — a cadeia hexadecimal de 64 caracteres do Passo 4.
  • A lista ordenada de IDs elegíveis — todos os 1.000 IDs do Passo 2, em ordem canónica.
  • A impressão digital SHA-256 dos IDs — o hash de 64 caracteres do Passo 3. Confirma que a lista publicada não foi adulterada.
  • A versão do algoritmo — atualmente v1. Fixa o algoritmo de seleção exato, para que melhorias futuras nunca alterem retroativamente resultados antigos.
  • A versão do Ruby — fixa o tempo de execução da linguagem, uma vez que a ordenação exata do baralhamento depende dela.

Refaça os cálculos você mesmo — em cinco linhas

Se tiver o Ruby instalado (vem incluído no macOS e na maioria das distribuições Linux), pode reproduzir o sorteio exato em casa. Cada concurso publica o seu próprio eligible-ids.txt na sua página de verificação (padrão de URL: /results/<token>/verify) — o guia de verificação explica passo a passo como descarregá-lo. Copie a semente publicada e cole isto no irb:

require "digest"
seed = "PASTE_THE_PUBLISHED_SEED_HERE"
ids  = File.read("eligible-ids.txt").split("\n").map(&:to_i).sort

# (1) Sanity check the input: must equal the published SHA-256.
Digest::SHA256.hexdigest(ids.join("\n"))

# (2) Re-run the shuffle. First 3 items are winners 1..3 (in order);
#     the next 9 items are reserves 1..9.
ids.shuffle(random: Random.new(seed.to_i(16))).first(12)

Os 12 IDs saem exatamente na mesma ordem que o concurso publicou. Três vencedores, nove reservas, bit a bit idênticos. É isto que torna um sorteio Pick a Winner verificável em vez de meramente prometido — a matemática faz o trabalho, não a palavra do operador.

Por que é difícil manipular isto

  • A semente é impossível de adivinhar. 2²⁵⁶ possibilidades, geradas apenas após a lista elegível estar comprometida. Ninguém consegue pré-calcular quais os IDs que a semente favoreceria, porque a semente não existe até ao momento do sorteio.
  • A entrada está bloqueada. A impressão digital SHA-256 significa que não é possível adicionar silenciosamente um comentário de um amigo após ver a semente — a impressão digital mudaria e o sorteio deixaria de ser reproduzível.
  • O baralhamento é mecânico. Assim que a semente e a lista ordenada existem, os vencedores estão determinados. Nenhuma decisão humana se interpõe entre eles. Qualquer ajuste posterior seria detetável no momento em que alguém refizesse os cálculos.
  • O recibo é público. Semente, lista, hash, versão do algoritmo, versão do Ruby — os cinco são publicados. Não existe nenhuma parte privada do sorteio que o operador pudesse alterar sem que todos pudessem ver.