RSA willekeurig op blockchain

Er is een probleem: het is moeilijk om een ​​willekeurig getal te genereren in een gedecentraliseerd netwerk. Bijna alle blockchains zijn dit al tegengekomen. In netwerken waar er geen vertrouwen tussen gebruikers bestaat, lost het creëren van een onmiskenbaar willekeurig getal veel problemen op.

In dit artikel vertellen we je hoe we het probleem hebben opgelost met games als voorbeeld. De eerste van hen was Golven kerstboom. Voor de ontwikkeling hadden we een generator voor willekeurige getallen nodig.

RSA willekeurig op blockchain

Aanvankelijk waren we van plan een getal te genereren op basis van informatie uit de blockchain. Toen werd echter duidelijk: het aantal zou gemanipuleerd kunnen worden, waardoor de oplossing niet geschikt is.

We hebben een oplossing bedacht: gebruik het commit-expand-schema. De server raadde een getal van 1 tot 5, voegde er een salt aan toe en hashte vervolgens het resultaat met behulp van Keccak-functies. De server heeft vooraf het slimme contract met het reeds opgeslagen nummer geïmplementeerd. Het blijkt dat het spel er op neerkomt dat de gebruiker het getal raadt dat verborgen is door de hash.

De speler plaatste een weddenschap en de server stuurde het verborgen nummer en ‘zout’ naar het slimme contract. In eenvoudige bewoordingen onthulde hij de kaarten. Daarna controleerde de server de cijfers en besliste of de gebruiker had gewonnen of verloren.

Als de server geen nummer of “salt” ter verificatie stuurde, won de gebruiker. In dit geval was het voor elk spel nodig om vooraf een slim contract in te zetten en daarin potentiële winsten op te nemen. Het bleek lastig, tijdrovend en duur. Er was toen geen andere veilige oplossing.

Onlangs stelde het Tradisys-team voor om een ​​functie aan het Waves-protocol toe te voegen rsaVerify(). Het controleert de geldigheid van de RSA-handtekening op basis van de publieke en private sleutel. Als gevolg hiervan is de functie toegevoegd.

We hebben drie spellen ontwikkeld: Zegt Roller, Coin Flip и Rijd op golven. Ze implementeren allemaal willekeurige nummertechnologie. Laten we uitzoeken hoe het werkt.

RSA willekeurig op blockchain

Laten we eens kijken naar het genereren van een willekeurig getal met Ride on Waves als voorbeeld. Het slimme contract is te vinden hier.

Ga naar tabblad Script en selecteer Gedecompileerd. U ziet de slimme contractcode (ook wel script genoemd).

RSA willekeurig op blockchain

De slimme contractcode bevat een reeks functies. Degenen die zijn gemarkeerd als @Callable kunnen worden gestart met Aanroeptransacties. Wij zijn geïnteresseerd in twee functies: weddenschap и intrekken:

  • func-weddenschap (playerChoice)
  • func intrekken(gameId,rsaSign)

1. De gebruiker selecteert de lengte van het segment en de inzetgrootte.

RSA willekeurig op blockchain

2. De klant maakt een weddenschapsfunctie aan. Voor de afbeelding hierboven zou dat zo zijn inzet("50").

3. De client verzendt een Invocation-transactie naar het slimme contractadres (broadcast InvocationTx). De transactie bevat de weddenschapsfunctie als callparameter. Dit betekent dat de Invocation-transactie de uitvoering van de weddenschapsfunctie (keuze: String) op het slimme contract activeert.

RSA willekeurig op blockchain

4. Overweeg de inzetfunctie:

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

De functie schrijft een nieuw spel naar de status van het slimme contract. Namelijk:

  • Unieke identificatie voor een nieuw spel (spel ID)
  • Spelstatus = VERZONDEN
  • Keuze van de speler (segmentlengte 50)
  • Publieke sleutel
  • Potentiële winst (afhankelijk van de inzet van de speler)

RSA willekeurig op blockchain

Zo ziet een datarecord in de blockchain eruit (sleutelwaarde):

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

"Sleutel" (sleutel) – spel ID nieuw spel. De overige gegevens bevinden zich in de regel van het veld “waarde”. Deze vermeldingen worden opgeslagen op het tabblad Data slim contract:

RSA willekeurig op blockchain

RSA willekeurig op blockchain

5. De server “kijkt” naar het slimme contract en vindt de verzonden transactie (nieuw spel) met behulp van de blockchain Api. De Game-ID van het nieuwe spel is al vastgelegd in de blockchain, waardoor deze niet meer kan worden gewijzigd of beïnvloed

6. De server genereert een terugtrekkingsfunctie (gameId, rsaSign). Bijvoorbeeld zoals dit:

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

7. De server verzendt een Invocation-transactie naar het slimme contract (broadcast InvocationTx). De transactie bevat een aanroep naar de gevormde opnamefunctie (gameId, rsaSign):

RSA willekeurig op blockchain

De functie bevat spel ID nieuw spel en het resultaat van RSA-ondertekening van een unieke identificatie met een privésleutel. Het handtekeningresultaat is ongewijzigd.

Wat betekent dit?

We nemen dezelfde waarde (game-ID) en passen hierop de RSA-handtekeningmethode toe. We zullen altijd hetzelfde resultaat krijgen. Dit is hoe het RSA-algoritme werkt. Het uiteindelijke getal kan niet worden gemanipuleerd, omdat de game-ID en het resultaat van het toepassen van RSA niet bekend zijn. Een getal kiezen is ook zinloos.

8. Blockchain accepteert de transactie. Het voert de terugtrekkingsfunctie uit (gameId, rsaSign)

9. Binnen de opnamefunctie vindt opname plaats GenereRandInt-functies (gameId, rsaSign). Dit is een willekeurige nummergenerator

# @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 - en er is een willekeurig getal.

Eerst wordt de string genomen, die het resultaat is van de RSA-handtekening spel ID prive sleutel (rsaTeken). Vervolgens gehasht met SHA-256 (sha256(rsaTeken)).

We kunnen de uitkomst van de handtekening en de daaropvolgende hashing niet voorspellen. Daarom is het onmogelijk om het genereren van een willekeurig getal te beïnvloeden. Om een ​​getal in een bepaald bereik te krijgen (bijvoorbeeld van 1 tot 100), gebruikt u de toInt-conversiefunctie en %100 (vergelijkbaar met mod).

Aan het begin van het artikel noemden we de functie rsaVerify(), waarmee u de geldigheid van een RSA-handtekening kunt controleren met behulp van een privésleutel en een openbare sleutel. Hier is het GenerateRandInt(gameId,rsaSign)-gedeelte:

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

De publieke sleutel RSAPUBLIC en de rsaSign-string worden doorgegeven aan de invoer. De handtekening wordt gecontroleerd op geldigheid. Het nummer wordt gegenereerd als de controle succesvol is. Anders gaat het systeem ervan uit dat de handtekening niet geldig is (ongeldige RSA-handtekening).

De server moet de game-ID ondertekenen met een privésleutel en binnen 2880 blokken een geldige Rsa-handtekening sturen. De parameter wordt geconfigureerd bij de implementatie van het slimme contract. Als er niets gebeurt binnen de toegewezen tijd, wint de gebruiker. In dit geval moet de prijs zelf naar uw adres worden verzonden. Het blijkt dat het “voor de server niet rendabel is om vals te spelen”, omdat dit tot verlies leidt. Hieronder ziet u een voorbeeld.

RSA willekeurig op blockchain

De gebruiker speelt Zegt Roller. Ik heb 2 van de 6 zijden van de kubus gekozen, de inzet is 14 WAVES. Als de server binnen de opgegeven tijd (2880 blokken) geen geldige RSA-handtekening naar het slimme contract stuurt, neemt de gebruiker 34.44 WAVES.

Om getallen in games te genereren, gebruiken we een orakel: een extern, niet-blockchain-systeem. De server voert een RSA-handtekening van de game-ID uit. Het slimme contract controleert de geldigheid van de handtekening en bepaalt de winnaar. Als de server niets verzendt, wint de gebruiker automatisch.

Dit is een eerlijke generatiemethode, omdat manipulatie technisch onmogelijk is. Alle Tradisys-spellen werken op basis van het beschreven algoritme. Dit is hoe blockchain-spellen werken. Alles is transparant en controleerbaar. Er zijn geen analogen van een dergelijk systeem in een andere blockchain. Dit is een redelijke willekeurigheid.

Bron: www.habr.com

Voeg een reactie