Cómo funciona un sorteo — un ejemplo real

Recorre un sorteo real de principio a fin: 1.000 comentarios elegibles, 3 ganadores, 9 reservas. Sin tecnicismos, sin rodeos.

El escenario

Imagina que el concurso ha terminado. Los comentarios han sido obtenidos, los filtros del concurso se han ejecutado y 1.000 participaciones son elegibles. El premio otorga 3 ganadores con 9 reservas, por si alguno de los ganadores no puede ser contactado. Aquí está la probabilidad por participación — idéntica para cada uno de los 1.000 comentarios elegibles, independientemente de cuándo fue publicado o de la longitud del nombre del comentarista.

Resultado Probabilidad para cualquier participación
Sorteado como ganador principal (puestos 1–3) 3 de cada 1.000 — 0,30%
Sorteado como reserva (puestos 4–12) 9 de cada 1.000 — 0,90%
Sorteado en cualquier puesto ganador 12 de cada 1.000 — 1,20%

Nada de esto cambia si el concurso tiene 444 comentarios o 444.444. El algoritmo es idéntico. Solo cambia el denominador.

Paso 1 — Recopilar y filtrar las participaciones

La aplicación obtiene cada comentario de la publicación de Facebook o Instagram que conectaste, luego aplica los filtros del concurso — duplicados, palabras bloqueadas, reglas de antigüedad de cuenta, lo que sea que se haya configurado. Lo que sobrevive es el conjunto elegible. En nuestro escenario son 1.000 comentarios. Cada uno tiene una fila en la base de datos con un ID numérico único; esos 1.000 IDs son sobre los que opera el resto del sorteo.

Paso 2 — Ordenarlos en un orden canónico

Antes de que ocurra algo aleatorio, la aplicación ordena los 1.000 IDs en estricto orden numérico ascendente — 17, 142, 203, 1058, 9941, … — y descarta el orden en que llegaron. ¿Por qué? Porque Facebook puede devolver los comentarios en distintos órdenes según la paginación, la hora del día o cambios en el backend. Si el sorteo usara el orden de Facebook, dos obtenciones podrían producir ganadores diferentes con la misma semilla aleatoria. Ordenar primero fija la entrada en una lista canónica, de modo que la semilla sola determina el resultado.

Paso 3 — Bloquear la lista de entrada con un hash SHA-256

La lista ordenada se procesa con SHA-256 — una función hash criptográfica — produciendo una huella de 64 caracteres. La huella, junto con la lista completa, se guarda en el registro del concurso. A partir de este momento, cualquiera que inspeccione el concurso puede confirmar que la lista elegible no ha sido alterada: vuelve a calcular el hash de la lista publicada, compáralo con la huella guardada, y un solo ID modificado produce un hash completamente diferente. No hay manera de añadir o eliminar un comentario silenciosamente después de este paso sin que sea visible.

Paso 4 — Generar una semilla aleatoria de 256 bits

La aplicación solicita a la fuente aleatoria criptográfica del sistema operativo (SecureRandom.hex(32)) 32 bytes de aleatoriedad impredecible, y almacena el resultado como una cadena hexadecimal de 64 caracteres — por ejemplo a3f1…ce. 256 bits significan 2²⁵⁶ ≈ 10⁷⁷ semillas posibles. Para tener perspectiva, el universo observable contiene aproximadamente 10⁸⁰ átomos. Nadie — ni el creador del concurso, ni el operador, ni un atacante que observe desde fuera — puede predecir o adivinar esta semilla antes de que sea generada.

Paso 5 — Mezclar los 1.000 IDs y tomar los primeros 12

La semilla inicializa un motor de mezcla determinista, que luego realiza un algoritmo de Fisher–Yates sobre los 1.000 IDs ordenados. Fisher–Yates es el algoritmo estándar de mezcla justa — cada una de las 1.000 participaciones tiene igual probabilidad de terminar en cualquier posición. Tras la mezcla, la aplicación toma las primeras 12 participaciones. Ese es todo el paso de selección: mezclar, tomar 12.

Paso 6 — Asignar posiciones

Las 12 participaciones seleccionadas se recorren en orden. Las primeras tres se convierten en ganadores 1, 2 y 3, y las siguientes nueve en reservas 1 a 9. Las 988 participaciones elegibles restantes se registran como no seleccionadas. Los comentarios que fueron filtrados anteriormente se marcan como descalificados con el motivo específico por el que no cumplieron los requisitos.

Paso 7 — Publicar todo

Finalmente, la aplicación guarda cinco piezas de evidencia en el registro del concurso — todas de lectura pública. Sin ellas, el resultado sería una caja negra. Con ellas, cualquiera puede reproducir el sorteo completo en casa y confirmar que los ganadores publicados son los únicos ganadores que la semilla podría haber producido.

Qué se publica con cada sorteo

Cada uno de estos datos se almacena en el concurso y se expone a través de las páginas públicas de verificación. En conjunto hacen que el sorteo sea completamente reproducible — mismas entradas, mismas salidas, siempre.

  • La semilla aleatoria de 256 bits — la cadena hexadecimal de 64 caracteres del Paso 4.
  • La lista ordenada de IDs elegibles — los 1.000 IDs del Paso 2, en orden canónico.
  • La huella SHA-256 de los IDs — el hash de 64 caracteres del Paso 3. Confirma que la lista publicada no ha sido manipulada.
  • La versión del algoritmo — actualmente v1. Fija el algoritmo de selección exacto, de modo que las mejoras futuras nunca cambien retroactivamente los resultados anteriores.
  • La versión de Ruby — fija el entorno de ejecución del lenguaje, ya que el orden exacto de la mezcla depende de él.

Reproduce el cálculo tú mismo — en cinco líneas

Si tienes Ruby instalado (viene preinstalado en macOS y en la mayoría de distribuciones Linux), puedes reproducir el sorteo exacto en casa. Cada concurso publica su propio eligible-ids.txt en su página de verificación (patrón de URL: /results/<token>/verify) — la guía de verificación explica paso a paso cómo descargarlo. Copia la semilla publicada y pega esto en 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)

Los 12 IDs salen exactamente en el mismo orden que publicó el concurso. Tres ganadores, nueve reservas, bit a bit idénticos. Eso es lo que hace que un sorteo de Pick a Winner sea verificable en lugar de simplemente prometido — las matemáticas hacen el trabajo, no la palabra del operador.

Por qué esto es difícil de manipular

  • La semilla es imposible de adivinar. 2²⁵⁶ posibilidades, generadas solo después de que la lista elegible está confirmada. Nadie puede precalcular qué IDs favorecería la semilla, porque la semilla no existe hasta el momento del sorteo.
  • La entrada está bloqueada. La huella SHA-256 significa que no puedes añadir silenciosamente el comentario de un amigo después de ver la semilla — la huella cambiaría y el sorteo ya no sería reproducible.
  • La mezcla es mecánica. Una vez que existen la semilla y la lista ordenada, los ganadores están determinados. No hay ninguna decisión humana entre ellos. Cualquier modificación posterior aparecería como una discrepancia en el momento en que alguien reproduzca el cálculo.
  • El comprobante es público. Semilla, lista, hash, versión del algoritmo, versión de Ruby — los cinco están publicados. No hay ninguna parte privada del sorteo que el operador pueda cambiar sin que todos puedan verlo.