RSA aleatorio en blockchain

Hai un problema: é difícil xerar un número aleatorio nunha rede descentralizada. Case todas as cadeas de bloques xa se atoparon con isto. De feito, en redes onde non hai confianza entre usuarios, a creación dun número aleatorio innegable resolve moitos problemas.

Neste artigo contámosche como conseguimos resolver o problema usando xogos como exemplo. O primeiro deles foi Olas Árbore de Nadal. Para o desenvolvemento, necesitabamos un xerador de números aleatorios.

RSA aleatorio en blockchain

Inicialmente, planeamos xerar un número baseado na información da cadea de bloques. Non obstante, entón quedou claro: o número podería manipularse, o que significa que a solución non é adecuada.

Creamos unha solución: use o esquema commit-expand. O servidor adiviñou un número do 1 ao 5, engadiulle un sal e, a continuación, dividiu o resultado usando Funcións de Keccak. O servidor despregou o contrato intelixente co número xa gardado de antemán. Acontece que o xogo redúcese a que o usuario adiviñe o número que oculta o hash.

O xogador fixo unha aposta e o servidor enviou o número oculto e o "sal" ao contrato intelixente. En termos sinxelos, revelou as cartas. Despois diso, o servidor comprobou os números e decidiu se o usuario gañaba ou perdeu.

Se o servidor non enviou un número ou "sal" para a verificación, o usuario gañaba. Neste caso, para cada xogo era necesario despregar previamente un contrato intelixente e incluír nel as posibles ganancias. Resultou incómodo, lento e caro. Daquela non había outra solución segura.

Recentemente, o equipo de Tradisys propuxo engadir unha función ao protocolo Waves rsaVerify(). Comproba a validez da sinatura RSA baseándose na clave pública e privada. Como resultado, engadiuse a función.

Desenvolvemos tres xogos: Rolo de dados, Flip de moeda и Ride On Waves. Cada un implementa a tecnoloxía de números aleatorios. Imos descubrir como funciona.

RSA aleatorio en blockchain

Vexamos como xerar un número aleatorio usando Ride on Waves como exemplo. Pódese atopar o contrato intelixente aquí.

Vai á lapela Escrita e selecciona Descompilado. Verás o código do contrato intelixente (tamén coñecido como script).

RSA aleatorio en blockchain

O código de contrato intelixente contén un conxunto de funcións. Os marcados como @Callable pódense iniciar usando Transaccións de invocación. Interésanos dúas funcións: apostar и retirar:

  • función aposta (playerChoice)
  • función retirar (gameId,rsaSign)

1. O usuario selecciona a lonxitude do segmento e o tamaño da aposta.

RSA aleatorio en blockchain

2. O cliente crea unha función de aposta. Para a imaxe de arriba sería aposta ("50").

3. O cliente envía unha transacción de Invocación ao enderezo do contrato intelixente (difusión InvocationTx). A transacción contén a función de aposta como parámetro de chamada. Isto significa que a transacción de Invocación desencadea a execución da función de aposta (elección: Cadena) no contrato intelixente.

RSA aleatorio en blockchain

4. Considere a función aposta:

@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)))
                    }
    }

A función escribe un novo xogo no estado do contrato intelixente. A saber:

  • Identificador único para un novo xogo (ID do xogo)
  • Estado do xogo = ENVIADO
  • A elección do xogador (longitude do segmento 50)
  • Chave pública
  • Ganancias potenciais (dependendo da aposta do xogador)

RSA aleatorio en blockchain

Así se ve un rexistro de datos na cadea de bloques (valor clave):

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

"Chave" (clave) - ID do xogo novo xogo. Os datos restantes están contidos na liña do campo "valor". Estas entradas gárdanse na pestana Data contrato intelixente:

RSA aleatorio en blockchain

RSA aleatorio en blockchain

5. O servidor "mira" o contrato intelixente e atopa a transacción enviada (xogo novo) mediante a cadea de bloques Api. O ID de xogo do novo xogo xa está rexistrado na cadea de bloques, o que significa que xa non se pode cambiar nin influír

6. O servidor xera unha función de retirada (gameId, rsaSign). Por exemplo, así:

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

7. O servidor envía unha transacción de Invocación ao contrato intelixente (difusión InvocationTx). A transacción contén unha chamada á función de retirada formada (gameId, rsaSign):

RSA aleatorio en blockchain

A función contén ID do xogo novo xogo e o resultado da sinatura RSA dun identificador único cunha clave privada. O resultado da sinatura non se modifica.

O que significa isto?

Tomamos o mesmo valor (identificador do xogo) e aplicamoslle o método de sinatura RSA. Sempre teremos o mesmo resultado. Así funciona o algoritmo RSA. Non se pode manipular o número final, xa que non se coñece a identificación do xogo nin o resultado da aplicación de RSA. Elixir un número tamén non ten sentido.

8. Blockchain acepta a transacción. Executa a función de retirada (gameId, rsaSign)

9. Dentro da función de retirada, prodúcese a retirada Funcións GenerateRandInt (gameId, rsaSign). Este é un xerador 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")
    }

fila - e hai un número aleatorio.

En primeiro lugar, tómase a cadea, que é o resultado da sinatura RSA ID do xogo chave privada (rsaSign). Despois hash con SHA-256 (sha256 (rsaSign)).

Non podemos prever o resultado da sinatura e do hash posterior. Polo tanto, é imposible influír na xeración dun número aleatorio. Para obter un número nun intervalo determinado (por exemplo, do 1 ao 100), use a función de conversión toInt e % 100 (semellante a mod).

Ao comezo do artigo mencionamos a función rsaVerify(), que che permite comprobar a validez dunha sinatura RSA usando unha clave privada contra unha pública. Aquí está a parte GenerateRandInt(gameId,rsaSign):

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

A chave pública RSAPUBLIC e a cadea rsaSign pásanse á entrada. Compróbase a validez da sinatura. O número xérase se a comprobación ten éxito. En caso contrario, o sistema considera que a sinatura non é válida (Sinatura RSA non válida).

O servidor debe asinar o identificador do xogo cunha clave privada e enviar unha sinatura Rsa válida dentro de 2880 bloques. O parámetro configúrase ao despregar o contrato intelixente. Se non ocorre nada no tempo previsto, o usuario gaña. Neste caso, o premio deberá enviarse vostede mesmo ao seu enderezo. Resulta que "non é rendible que o servidor faga trampas", porque isto leva a perdas. A continuación móstrase un exemplo.

RSA aleatorio en blockchain

O usuario está xogando Rolo de dados. Escollín 2 dos 6 lados do cubo, a aposta é de 14 ONDAS. Se o servidor non envía unha sinatura RSA válida ao contrato intelixente dentro do tempo especificado (2880 bloques), o usuario tomará 34.44 WAVES.

Para xerar números nos xogos, usamos un oráculo, un sistema externo sen cadea de bloques. O servidor realiza unha sinatura RSA do ID do xogo. O contrato intelixente comproba a validez da sinatura e determina o gañador. Se o servidor non envía nada, o usuario gaña automaticamente.

Este é un método de xeración honesto, porque a manipulación é tecnicamente imposible. Todos os xogos de Tradisys funcionan baseándose no algoritmo descrito. Así funcionan os xogos blockchain. Todo é transparente e verificable. Non hai análogos deste sistema en ningunha outra cadea de bloques. Este é un aleatorio xusto.

Fonte: www.habr.com

Engadir un comentario