RSA aléatoire sur blockchain

Il y a un problème : il est difficile de générer un nombre aléatoire dans un réseau décentralisé. Presque toutes les blockchains ont déjà rencontré ce problème. En effet, dans les réseaux où il n’y a pas de confiance entre les utilisateurs, créer un nombre aléatoire indéniable résout de nombreux problèmes.

Dans cet article, nous vous expliquons comment nous avons réussi à résoudre le problème en utilisant les jeux comme exemple. Le premier d'entre eux était Arbre de Noël des vagues. Pour le développement, nous avions besoin d'un générateur de nombres aléatoires.

RSA aléatoire sur blockchain

Initialement, nous avions prévu de générer un numéro basé sur les informations de la blockchain. Cependant, il est alors devenu clair : le nombre pouvait être manipulé, ce qui signifie que la solution n'était pas adaptée.

Nous avons trouvé une solution de contournement : utilisez le schéma commit-expand. Le serveur a deviné un nombre de 1 à 5, y a ajouté du sel, puis a haché le résultat en utilisant Fonctions Keccak. Le serveur a déployé à l'avance le contrat intelligent avec le numéro déjà enregistré. Il s'avère que le jeu se résume à ce que l'utilisateur devine le numéro caché par le hachage.

Le joueur a placé un pari et le serveur a envoyé le numéro caché et le « sel » au contrat intelligent. En termes simples, il a dévoilé les cartes. Après cela, le serveur vérifiait les numéros et décidait si l'utilisateur avait gagné ou perdu.

Si le serveur n'envoyait pas de numéro ou de « sel » pour vérification, l'utilisateur gagnait. Dans ce cas, pour chaque jeu, il fallait déployer au préalable un contrat intelligent et y inclure les gains potentiels. Cela s’est avéré peu pratique, long et coûteux. À cette époque, il n’existait aucune autre solution sûre.

Récemment, l'équipe Tradisys a proposé d'ajouter une fonction au protocole Waves rsaVerify(). Il vérifie la validité de la signature RSA en fonction de la clé publique et privée. En conséquence, la fonctionnalité a été ajoutée.

Nous avons développé trois jeux : Dit Roller, Coin Flip и Monter sur les vagues. Chacun implémente la technologie des nombres aléatoires. Voyons comment cela fonctionne.

RSA aléatoire sur blockchain

Voyons générer un nombre aléatoire en utilisant Ride on Waves comme exemple. Le contrat intelligent peut être trouvé ici.

Cliquez sur l'onglet scénario et sélectionnez Décompilé. Vous verrez le code du contrat intelligent (alias script).

RSA aléatoire sur blockchain

Le code du contrat intelligent contient un ensemble de fonctions. Ceux marqués comme @Callable peuvent être lancés en utilisant Opérations d'appel. Nous nous intéressons à deux fonctions : parier и renoncer:

  • pari fonctionnel (playerChoice)
  • func retirer (gameId, rsaSign)

1. L'utilisateur sélectionne la longueur du segment et le montant de la mise.

RSA aléatoire sur blockchain

2. Le client crée une fonction de pari. Pour l'image ci-dessus, ce serait pari("50").

3. Le client envoie une transaction d'invocation à l'adresse du contrat intelligent (diffusion InvocationTx). La transaction contient la fonction de pari comme paramètre d'appel. Cela signifie que la transaction Invocation déclenche l'exécution de la fonction de pari (choix : String) sur le contrat intelligent.

RSA aléatoire sur blockchain

4. Considérez la fonction de pari :

@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 fonction écrit un nouveau jeu dans l'état du contrat intelligent. À savoir:

  • Identifiant unique pour un nouveau jeu (identifiant de jeu)
  • État du jeu = SOUMIS
  • Au choix du joueur (longueur du segment 50)
  • Clé publique
  • Gains potentiels (en fonction de la mise du joueur)

RSA aléatoire sur blockchain

Voici à quoi ressemble un enregistrement de données dans la blockchain (valeur-clé) :

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

"Clé" (clé) – identifiant de jeu nouveau jeu. Les données restantes sont contenues dans la ligne du champ « valeur ». Ces entrées sont stockées dans l'onglet Données contrat intelligent :

RSA aléatoire sur blockchain

RSA aléatoire sur blockchain

5. Le serveur « regarde » le contrat intelligent et trouve la transaction envoyée (nouveau jeu) à l'aide de l'API blockchain. L'identifiant du nouveau jeu est déjà enregistré dans la blockchain, ce qui signifie qu'il ne peut plus être modifié ou influencé.

6. Le serveur génère une fonction de retrait (gameId, rsaSign). Par exemple, comme ceci :

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

7. Le serveur envoie une transaction d'invocation au contrat intelligent (diffusion InvocationTx). La transaction contient un appel à la fonction de retrait formée (gameId, rsaSign) :

RSA aléatoire sur blockchain

La fonction contient identifiant de jeu nouveau jeu et résultat de la signature RSA d'un identifiant unique avec une clé privée. Le résultat de la signature est inchangé.

Qu'est-ce que cela signifie?

Nous prenons la même valeur (identifiant du jeu) et lui appliquons la méthode de signature RSA. Nous obtiendrons toujours le même résultat. C'est ainsi que fonctionne l'algorithme RSA. Le nombre final ne peut pas être manipulé, car l'identifiant du jeu et le résultat de l'application de RSA ne sont pas connus. Choisir un numéro est également inutile.

8. Blockchain accepte la transaction. Il exécute la fonction de retrait (gameId, rsaSign)

9. Dans la fonction de retrait, le retrait se produit Fonctions GénérerRandInt (ID de jeu, rsaSign). Ceci est un générateur de nombres aléatoires

# @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 - et il y a un nombre aléatoire.

Tout d'abord, la chaîne est extraite, ce qui est le résultat de la signature RSA. identifiant de jeu Clé privée (rsaSign). Puis haché avec SHA-256 (sha256(rsaSign)).

Nous ne pouvons pas prédire le résultat de la signature et du hachage ultérieur. Il est donc impossible d’influencer la génération d’un nombre aléatoire. Pour obtenir un nombre dans une certaine plage (par exemple, de 1 à 100), utilisez la fonction de conversion toInt et %100 (similaire à mod).

Au début de l'article nous avons évoqué la fonction rsaVerify(), qui vous permet de vérifier la validité d'une signature RSA à l'aide d'une clé privée par rapport à une clé publique. Voici la partie GenerateRandInt(gameId,rsaSign) :

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

La clé publique RSAPUBLIC et la chaîne rsaSign sont transmises à l'entrée. La validité de la signature est vérifiée. Le numéro est généré si le contrôle est réussi. Dans le cas contraire, le système considère que la signature n'est pas valide (Invalid RSA signature).

Le serveur doit signer l'identifiant du jeu avec une clé privée et envoyer une signature Rsa valide dans les 2880 XNUMX blocs. Le paramètre est configuré lors du déploiement du contrat intelligent. Si rien ne se passe dans le temps imparti, l'utilisateur gagne. Dans ce cas, le prix doit être envoyé vous-même à votre adresse. Il s'avère qu'il n'est « pas rentable pour le serveur de tricher », car cela entraîne des pertes. Ci-dessous un exemple.

RSA aléatoire sur blockchain

L'utilisateur joue Dit Roller. J'ai choisi 2 des 6 faces du cube, la mise est de 14 VAGUES. Si le serveur n'envoie pas de signature RSA valide au contrat intelligent dans le délai spécifié (2880 blocs), l'utilisateur prendra 34.44 VAGUES.

Pour générer des nombres dans les jeux, nous utilisons un oracle – un système externe sans blockchain. Le serveur effectue une signature RSA de l'identifiant du jeu. Le contrat intelligent vérifie la validité de la signature et détermine le gagnant. Si le serveur n'envoie rien, alors l'utilisateur gagne automatiquement.

Il s’agit d’une méthode de génération honnête, car la manipulation est techniquement impossible. Tous les jeux Tradisys fonctionnent sur la base de l'algorithme décrit. C'est ainsi que fonctionnent les jeux blockchain. Tout est transparent et vérifiable. Il n’existe aucun analogue d’un tel système dans aucune autre blockchain. C'est un peu aléatoire.

Source: habr.com

Ajouter un commentaire