RSA casuale su blockchain

C'è un problema: è difficile generare un numero casuale in una rete decentralizzata. Quasi tutte le blockchain lo hanno già riscontrato. Infatti, nelle reti in cui non c’è fiducia tra gli utenti, la creazione di un numero casuale innegabile risolve molti problemi.

In questo articolo vi raccontiamo come siamo riusciti a risolvere il problema utilizzando i giochi come esempio. Il primo è stato Onde albero di Natale. Per lo sviluppo avevamo bisogno di un generatore di numeri casuali.

RSA casuale su blockchain

Inizialmente, avevamo pianificato di generare un numero basato sulle informazioni della blockchain. Poi però è diventato chiaro: il numero potrebbe essere manipolato, il che significa che la soluzione non è adatta.

Abbiamo trovato una soluzione alternativa: utilizzare lo schema commit-expand. Il server ha indovinato un numero da 1 a 5, vi ha aggiunto un sale e quindi ha eseguito l'hashing del risultato utilizzando Funzioni Keccak. Il server ha distribuito in anticipo lo smart contract con il numero già salvato. Si scopre che il gioco si riduce all'utente che indovina il numero nascosto dall'hash.

Il giocatore ha piazzato una scommessa e il server ha inviato il numero nascosto e il "sale" allo smart contract. In parole povere, ha scoperto le carte. Successivamente, il server controlla i numeri e decide se l'utente ha vinto o perso.

Se il server non inviava un numero o un “salt” per la verifica, l’utente vinceva. In questo caso, per ogni gioco era necessario implementare in anticipo uno smart contract e includervi potenziali vincite. Si è rivelato scomodo, dispendioso in termini di tempo e costoso. A quel tempo non esisteva altra soluzione sicura.

Recentemente, il team di Tradisys ha proposto di aggiungere una funzione al protocollo Waves rsaVerify(). Verifica la validità della firma RSA in base alla chiave pubblica e privata. Di conseguenza, la funzionalità è stata aggiunta.

Abbiamo sviluppato tre giochi: Dadi Roller, Coin Flip и Cavalca sulle onde. Ognuno implementa la tecnologia dei numeri casuali. Scopriamo come funziona.

RSA casuale su blockchain

Diamo un'occhiata alla generazione di un numero casuale utilizzando Ride on Waves come esempio. Il contratto intelligente può essere trovato qui.

Vai alla scheda Copione e selezionare Decompilato. Vedrai il codice del contratto intelligente (noto anche come script).

RSA casuale su blockchain

Il codice del contratto intelligente contiene una serie di funzioni. Quelli contrassegnati come @Callable possono essere avviati utilizzando Transazioni di invocazione. A noi interessano due funzioni: scommettere и ritirare:

  • funzione scommessa (playerChoice)
  • funzione ritiro(gameId,rsaSign)

1. L'utente seleziona la lunghezza del segmento e l'importo della scommessa.

RSA casuale su blockchain

2. Il cliente crea una funzione di scommessa. Per l'immagine sopra lo sarebbe scommessa("50").

3. Il client invia una transazione di chiamata all'indirizzo del contratto intelligente (trasmette InvocationTx). La transazione contiene la funzione di scommessa come parametro di chiamata. Ciò significa che la transazione di Invocazione attiva l'esecuzione della funzione di scommessa (scelta: Stringa) sullo smart contract.

RSA casuale su blockchain

4. Considera la funzione di scommessa:

@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 funzione scrive un nuovo gioco nello stato del contratto intelligente. Vale a dire:

  • Identificatore univoco per un nuovo gioco (identità di gioco)
  • Stato del gioco = INVIATO
  • A scelta del giocatore (lunghezza del segmento 50)
  • Chiave pubblica
  • Vincite potenziali (a seconda della scommessa del giocatore)

RSA casuale su blockchain

Ecco come appare un record di dati nella blockchain (valore-chiave):

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

"Chiave" (chiave) – identità di gioco nuovo gioco. I restanti dati sono contenuti nella riga del campo “valore”. Queste voci vengono memorizzate nella scheda Dati contratto intelligente:

RSA casuale su blockchain

RSA casuale su blockchain

5. Il server “guarda” lo smart contract e trova la transazione inviata (nuovo gioco) utilizzando l'Api blockchain. Il Game ID del nuovo gioco è già registrato nella blockchain, il che significa che non può più essere modificato o influenzato

6. Il server genera una funzione di prelievo (gameId, rsaSign). Ad esempio, in questo modo:

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

7. Il server invia una transazione di invocazione allo smart contract (trasmette InvocationTx). La transazione contiene una chiamata alla funzione di ritiro formattata (gameId, rsaSign):

RSA casuale su blockchain

La funzione contiene identità di gioco nuovo gioco e il risultato della firma RSA di un identificatore univoco con una chiave privata. Il risultato della firma è invariato.

Che cosa significa?

Prendiamo lo stesso valore (ID gioco) e gli applichiamo il metodo di firma RSA. Otterremo sempre lo stesso risultato. Ecco come funziona l'algoritmo RSA. Il numero finale non può essere manipolato, poiché l'ID del gioco e il risultato dell'applicazione dell'RSA non sono noti. Anche scegliere un numero è inutile.

8. Blockchain accetta la transazione. Esegue la funzione di prelievo (gameId, rsaSign)

9. All'interno della funzione di ritiro, avviene il ritiro Funzioni GeneraRandInt (ID gioco, rsaSign). Questo è un generatore di numeri casuali

# @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 - e c'è un numero casuale.

Per prima cosa viene presa la stringa che è il risultato della firma RSA identità di gioco chiave privata (rsaSign). Quindi eseguire l'hashing con SHA-256 (sha256(rsaSign)).

Non possiamo prevedere l'esito della firma e del successivo hashing. Pertanto, è impossibile influenzare la generazione di un numero casuale. Per ottenere un numero in un certo intervallo (ad esempio, da 1 a 100), utilizzare la funzione di conversione toInt e %100 (simile a mod).

All'inizio dell'articolo abbiamo menzionato la funzione rsaVerify(), che consente di verificare la validità di una firma RSA utilizzando una chiave privata rispetto a una pubblica. Ecco la parte GenerateRandInt(gameId,rsaSign):

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

All'input vengono passate la chiave pubblica RSAPUBLIC e la stringa rsaSign. Viene verificata la validità della firma. Il numero viene generato se il controllo ha esito positivo. In caso contrario il sistema considera la firma non valida (Firma RSA non valida).

Il server deve firmare l'ID del gioco con una chiave privata e inviare una firma Rsa valida entro 2880 blocchi. Il parametro viene configurato durante la distribuzione del contratto intelligente. Se non succede nulla entro il tempo assegnato, l'utente vince. In questo caso, il premio dovrà essere inviato tu stesso al tuo indirizzo. Si scopre che "non è redditizio per il server imbrogliare", perché ciò porta alla perdita. Di seguito è riportato un esempio.

RSA casuale su blockchain

L'utente sta giocando Dadi Roller. Ho scelto 2 dei 6 lati del cubo, la scommessa è 14 ONDE. Se il server non invia una firma RSA valida allo smart contract entro il tempo specificato (2880 blocchi), l'utente impiegherà 34.44 WAVES.

Per generare numeri nei giochi utilizziamo un oracolo, un sistema esterno non blockchain. Il server esegue una firma RSA dell'ID del gioco. Il contratto intelligente verifica la validità della firma e determina il vincitore. Se il server non invia nulla, l'utente vince automaticamente.

Questo è un metodo di generazione onesto, perché la manipolazione è tecnicamente impossibile. Tutti i giochi Tradisys funzionano in base all'algoritmo descritto. Ecco come funzionano i giochi blockchain. Tutto è trasparente e verificabile. Non esistono analoghi di un tale sistema in nessun’altra blockchain. Questo è un giusto casuale.

Fonte: habr.com

Aggiungi un commento