RSA aleatorio en blockchain

Hay un problema: es difícil generar un número aleatorio en una red descentralizada. Casi todas las cadenas de bloques ya se han encontrado con esto. De hecho, en redes donde no existe confianza entre los usuarios, crear un número aleatorio innegable resuelve muchos problemas.

En este artículo te contamos cómo logramos solucionar el problema usando juegos como ejemplo. El primero de ellos fue Árbol de Navidad de olas. Para el desarrollo, necesitábamos un generador de números aleatorios.

RSA aleatorio en blockchain

Inicialmente, planeamos generar un número basado en información de blockchain. Sin embargo, luego quedó claro: el número podría ser manipulado, lo que significa que la solución no es adecuada.

Se nos ocurrió una solución alternativa: utilizar el esquema de confirmación y expansión. El servidor adivinó un número del 1 al 5, le añadió sal y luego analizó el resultado usando Funciones de Keccak. El servidor implementó el contrato inteligente con el número ya guardado por adelantado. Resulta que el juego se reduce a que el usuario adivine el número oculto por el hash.

El jugador hizo una apuesta y el servidor envió el número oculto y la "sal" al contrato inteligente. En pocas palabras, reveló las cartas. Después de eso, el servidor verificó los números y decidió si el usuario ganó o perdió.

Si el servidor no envió un número o "sal" para verificación, el usuario ganó. En este caso, para cada juego era necesario implementar un contrato inteligente por adelantado e incluir en él ganancias potenciales. Resultó inconveniente, lento y costoso. En aquel momento no había otra solución segura.

Recientemente, el equipo de Tradisys propuso agregar una función al protocolo Waves rsaVerificar(). Comprueba la validez de la firma RSA en función de la clave pública y privada. Como resultado, se agregó la función.

Hemos desarrollado tres juegos: Rodillo de dados, Coin Flip и Montar sobre las olas. Cada uno implementa tecnología de números aleatorios. Averigüemos cómo funciona.

RSA aleatorio en blockchain

Veamos cómo generar un número aleatorio usando Ride on Waves como ejemplo. El contrato inteligente se puede encontrar aquí.

Ir a la pestaña Guión y seleccione Descompilado. Verá el código de contrato inteligente (también conocido como script).

RSA aleatorio en blockchain

El código de contrato inteligente contiene un conjunto de funciones. Aquellos marcados como @Callable se pueden iniciar usando Transacciones de invocación. Nos interesan dos funciones: apostar и retirar:

  • apuesta funcional (playerChoice)
  • func retirar(gameId,rsaSign)

1. El usuario selecciona la duración del segmento y el tamaño de la apuesta.

RSA aleatorio en blockchain

2. El cliente crea una función de apuesta. Para la imagen de arriba sería apuesta ("50").

3. El cliente envía una transacción de Invocación a la dirección del contrato inteligente (transmisión InvocationTx). La transacción contiene la función de apuesta como parámetro de llamada. Esto significa que la transacción de Invocación desencadena la ejecución de la función de apuesta (elección: Cadena) en el contrato inteligente.

RSA aleatorio en blockchain

4. Considere la función de apuesta:

@Callable(i)
func bet (playerChoice) = {
    let newGameNum = IncrementGameNum()
    let gameId = toBase58String(i.transactionId)
    let pmt = extract(i.payment)
    let betNotInWaves = isDefined(pmt.assetId)
    let feeNotInWaves = isDefined(pmt.assetId)
    let winAmt = ValidateBetAndDefineWinAmt(pmt.amount, playerChoice)
    let txIdUsed = isDefined(getString(this, gameId))
    if (betNotInWaves)
        then throw ("Bet amount must be in Waves")
        else if (feeNotInWaves)
            then throw ("Transaction's fee must be in Waves")
            else if (txIdUsed)
                then throw ("Passed txId had been used before. Game aborted.")
                else {
                    let playerPubKey58 = toBase58String(i.callerPublicKey)
                    let gameDataStr = FormatGameDataStr(STATESUBMITTED, playerChoice, playerPubKey58, height, winAmt, "")
                    ScriptResult(WriteSet(cons(DataEntry(RESERVATIONKEY, ValidateAndIncreaseReservedAmt(winAmt)), cons(DataEntry(GAMESCOUNTERKEY, newGameNum), cons(DataEntry(gameId, gameDataStr), nil)))), TransferSet(cons(ScriptTransfer(SERVER, COMMISSION, unit), nil)))
                    }
    }

La función escribe un nuevo juego en el estado del contrato inteligente. A saber:

  • Identificador único para un juego nuevo (ID del juego)
  • Estado del juego = ENVIADO
  • Elección del jugador (longitud del segmento 50)
  • Llave pública
  • Ganancias potenciales (dependiendo de la apuesta del jugador)

RSA aleatorio en blockchain

Así es como se ve un registro de datos en la cadena de bloques (clave-valor):

{
    "type": "string",
    "value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
    "key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
  }

"Llave llave) - ID del juego nuevo juego. Los datos restantes están contenidos en la línea del campo "valor". Estas entradas se almacenan en la pestaña Datos contrato inteligente:

RSA aleatorio en blockchain

RSA aleatorio en blockchain

5. El servidor "mira" el contrato inteligente y encuentra la transacción enviada (juego nuevo) utilizando la API de blockchain. La identificación del juego nuevo ya está registrada en la cadena de bloques, lo que significa que ya no se puede cambiar ni influir.

6. El servidor genera una función de retiro (gameId, rsaSign). Por ejemplo, así:

withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")

7. El servidor envía una transacción de Invocación al contrato inteligente (transmisión InvocationTx). La transacción contiene una llamada a la función de retiro formada (gameId, rsaSign):

RSA aleatorio en blockchain

La función contiene ID del juego nuevo juego y el resultado de la firma RSA de un identificador único con una clave privada. El resultado de la firma no ha cambiado.

¿Qué significa?

Tomamos el mismo valor (id del juego) y le aplicamos el método de firma RSA. Siempre obtendremos el mismo resultado. Así funciona el algoritmo RSA. El número final no se puede manipular, ya que no se conocen la identificación del juego ni el resultado de aplicar RSA. Elegir un número tampoco tiene sentido.

8. Blockchain acepta la transacción. Ejecuta la función de retiro (gameId, rsaSign)

9. Dentro de la función de retiro, se produce el retiro. Funciones GenerateRandInt (ID del juego, rsaSign). Este es un generador de números aleatorios.

# @return 1 ... 100
func GenerateRandInt (gameId,rsaSign) = {
   	# verify RSA signature to proof random
    let rsaSigValid = rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
    if (rsaSigValid)
        then {
            let rand = (toInt(sha256(rsaSign)) % 100)
            if ((0 > rand))
                then ((-1 * rand) + 1)
                else (rand + 1)
            }
        else throw ("Invalid RSA signature")
    }

rand - y hay un número aleatorio.

Primero se toma la cadena, que es el resultado de la firma RSA. ID del juego llave privada (rsaSign). Luego hash con SHA-256 (sha256(rsaSigno)).

No podemos predecir el resultado de la firma y el posterior hash. Por tanto, es imposible influir en la generación de un número aleatorio. Para obtener un número en un rango determinado (por ejemplo, de 1 a 100), use la función de conversión toInt y %100 (similar a mod).

Al principio del artículo mencionamos la función. rsaVerificar(), que le permite comparar la validez de una firma RSA utilizando una clave privada con una pública. Aquí está la parte GenerateRandInt(gameId,rsaSign):

rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)

La clave pública RSAPUBLIC y la cadena rsaSign se pasan a la entrada. Se comprueba la validez de la firma. El número se genera si la verificación es exitosa. En caso contrario, el sistema considera que la firma no es válida (Firma RSA no válida).

El servidor debe firmar la identificación del juego con una clave privada y enviar una firma Rsa válida dentro de 2880 bloques. El parámetro se configura al implementar el contrato inteligente. Si no ocurre nada dentro del tiempo asignado, el usuario gana. En este caso, el premio deberá ser enviado usted mismo a su dirección. Resulta que “no es rentable para el servidor hacer trampa”, porque esto genera pérdidas. A continuación se muestra un ejemplo.

RSA aleatorio en blockchain

El usuario esta jugando. Rodillo de dados. Elegí 2 de las 6 caras del cubo, la apuesta es 14 ONDAS. Si el servidor no envía una firma RSA válida al contrato inteligente dentro del tiempo especificado (2880 bloques), el usuario recibirá 34.44 WAVES.

Para generar números en los juegos, utilizamos un oráculo, un sistema externo que no es blockchain. El servidor realiza una firma RSA de la identificación del juego. El contrato inteligente verifica la validez de la firma y determina el ganador. Si el servidor no envía nada, el usuario gana automáticamente.

Este es un método de generación honesto, porque la manipulación es técnicamente imposible. Todos los juegos de Tradisys funcionan según el algoritmo descrito. Así funcionan los juegos blockchain. Todo es transparente y verificable. No existen análogos de un sistema de este tipo en ninguna otra cadena de bloques. Esta es una buena casualidad.

Fuente: habr.com

Añadir un comentario