RSA պատահական բլոկչեյնի վրա

Խնդիր կա՝ ապակենտրոնացված ցանցում դժվար է պատահական թիվ ստեղծել։ Գրեթե բոլոր բլոկչեյններն արդեն հանդիպել են դրան: Իրոք, ցանցերում, որտեղ օգտատերերի միջև վստահություն չկա, անհերքելի պատահական թվի ստեղծումը լուծում է բազմաթիվ խնդիրներ։

Այս հոդվածում մենք պատմում ենք, թե ինչպես մեզ հաջողվեց լուծել խնդիրը՝ օգտագործելով խաղերը որպես օրինակ: Դրանցից առաջինն էր Ալիքների տոնածառ. Զարգացման համար մեզ անհրաժեշտ էր պատահական թվերի գեներատոր:

RSA պատահական բլոկչեյնի վրա

Սկզբում մենք նախատեսում էինք բլոկչեյնից ստացված տեղեկատվության հիման վրա թվեր ստեղծել: Սակայն հետո պարզ դարձավ, որ թիվը կարելի է շահարկել, ինչը նշանակում է, որ լուծումը հարմար չէ։

Մենք մշակեցինք լուծում. օգտագործեք «commit-expand» սխեման: Սերվերը կռահեց 1-ից մինչև 5 թիվը, դրա վրա աղ ավելացրեց և այնուհետև հաշեց արդյունքը՝ օգտագործելով Keccak գործառույթները. Սերվերը նախապես գործարկել է խելացի պայմանագիրը արդեն պահպանված համարով: Պարզվում է, որ խաղը հանգում է նրան, որ օգտատերը գուշակում է հեշի կողմից թաքցված թիվը:

Խաղացողը խաղադրույք կատարեց, և սերվերը թաքնված համարն ու «աղը» ուղարկեց խելացի պայմանագրին: Պարզ ասած՝ նա բացահայտեց քարտերը։ Դրանից հետո սերվերը ստուգել է թվերը և որոշել՝ օգտատերը շահե՞լ է, թե՞ պարտվել։

Եթե ​​սերվերը ստուգման համար թիվ կամ «աղ» չի ուղարկել, օգտվողը շահել է: Այս դեպքում յուրաքանչյուր խաղի համար անհրաժեշտ էր նախապես խելացի պայմանագիր գործարկել և դրանում ներառել հնարավոր շահումները: Պարզվեց, որ դա անհարմար էր, ժամանակատար և թանկ: Այն ժամանակ այլ անվտանգ լուծում չկար։

Վերջերս Tradisys թիմն առաջարկեց գործառույթ ավելացնել Waves արձանագրությանը rsaVerify (). Այն ստուգում է RSA ստորագրության վավերականությունը՝ հիմնվելով հանրային և մասնավոր բանալիի վրա: Արդյունքում ֆունկցիան ավելացվեց։

Մենք մշակել ենք երեք խաղ. Dice Roller, Coin Flip и Ride On Waves. Յուրաքանչյուրն իրականացնում է պատահական թվերի տեխնոլոգիա: Եկեք պարզենք, թե ինչպես է այն աշխատում:

RSA պատահական բլոկչեյնի վրա

Եկեք նայենք պատահական թվի ստեղծմանը, օգտագործելով Ride on Waves որպես օրինակ: Խելացի պայմանագիրը կարելի է գտնել այստեղ.

Գնացեք ներդիր Ձեռագիր և ընտրել Ապակոմպիլացված. Դուք կտեսնեք խելացի պայմանագրի կոդը (aka script):

RSA պատահական բլոկչեյնի վրա

Խելացի պայմանագրի կոդը պարունակում է մի շարք գործառույթներ: Նրանք, որոնք նշված են որպես @Callable, կարող են գործարկվել՝ օգտագործելով Հրավիրման գործարքներ. Մեզ հետաքրքրում է երկու գործառույթ. գրազ и հեռանալ:

  • ֆունկցիոնալ խաղադրույք (playerChoice)
  • func դուրսբերում (gameId,rsaSign)

1. Օգտագործողը ընտրում է հատվածի երկարությունը և խաղադրույքի չափը:

RSA պատահական բլոկչեյնի վրա

2. Հաճախորդը ստեղծում է խաղադրույքի գործառույթ: Վերևի պատկերի համար դա կլիներ խաղադրույք («50»).

3. Հաճախորդը Invocation գործարք է ուղարկում խելացի պայմանագրի հասցեին (broadcast InvocationTx): Գործարքը պարունակում է խաղադրույքի գործառույթը որպես զանգի պարամետր: Սա նշանակում է, որ Invocation գործարքը գործարկում է խելացի պայմանագրի վրա խաղադրույքի ֆունկցիայի (ընտրություն՝ String) կատարումը:

RSA պատահական բլոկչեյնի վրա

4. Դիտարկենք խաղադրույքի գործառույթը.

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

Ֆունկցիան նոր խաղ է գրում խելացի պայմանագրի վիճակին: Այսինքն:

  • Եզակի նույնացուցիչ նոր խաղի համար (խաղի ID)
  • Խաղի վիճակ = ՆԵՐԿԱՅԱՑՎԱԾ
  • Խաղացողի ընտրություն (հատվածի երկարությունը 50)
  • Հանրային բանալի
  • Հնարավոր շահումներ (կախված խաղացողի խաղադրույքից)

RSA պատահական բլոկչեյնի վրա

Ահա թե ինչ տեսք ունի տվյալների գրառումը բլոկչեյնում (բանալին-արժեք).

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

«Բանալին» (բանալին) – խաղի ID Նոր խաղ. Մնացած տվյալները պարունակվում են «արժեք» դաշտի տողում: Այս գրառումները պահվում են ներդիրում Ամսաթիվ խելացի պայմանագիր.

RSA պատահական բլոկչեյնի վրա

RSA պատահական բլոկչեյնի վրա

5. Սերվերը «նայում» է խելացի պայմանագրին և գտնում է ուղարկված գործարքը (նոր խաղ)՝ օգտագործելով բլոկչեյն Api: Նոր խաղի Game ID-ն արդեն գրանցված է բլոկչեյնում, ինչը նշանակում է, որ այն այլևս չի կարող փոխվել կամ ազդել

6. Սերվերը առաջացնում է դուրսբերման ֆունկցիա (gameId, rsaSign): Օրինակ, այսպես.

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

7. Սերվերը Invocation գործարք է ուղարկում խելացի պայմանագրին (հեռարձակման InvocationTx): Գործարքը պարունակում է զանգ դեպի ձևավորված դուրսբերման գործառույթը (gameId, rsaSign).

RSA պատահական բլոկչեյնի վրա

Ֆունկցիան պարունակում է խաղի ID նոր խաղ և RSA-ի արդյունք՝ մասնավոր բանալիով եզակի նույնացուցիչի ստորագրման: Ստորագրության արդյունքն անփոփոխ է։

Ինչ է սա նշանակում.

Մենք վերցնում ենք նույն արժեքը (խաղի id) և դրա վրա կիրառում ենք RSA ստորագրության մեթոդը: Մենք միշտ նույն արդյունքն ենք ստանալու։ Այսպես է աշխատում RSA ալգորիթմը։ Վերջնական թիվը հնարավոր չէ շահարկել, քանի որ խաղի ID-ն և RSA-ի կիրառման արդյունքը հայտնի չեն: Թիվ ընտրելը նույնպես անիմաստ է:

8. Բլոկչեյնն ընդունում է գործարքը: Այն գործարկում է դուրսբերման գործառույթը (gameId, rsaSign)

9. Ներբեռնման գործառույթի ներսում տեղի է ունենում դուրսբերում GenerateRandInt գործառույթները (խաղի ID, rsaSign): Սա պատահական թվերի գեներատոր է

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

ռանտ - և կա պատահական թիվ:

Նախ վերցվում է տողը, որը RSA-ի ստորագրության արդյունքն է խաղի ID անձնական բանալի (rsaSign) Այնուհետև հեշավորվել է SHA-256-ով (sha256 (rsaSign)).

Մենք չենք կարող կանխատեսել ստորագրության և հետագա հաշինգի արդյունքը: Հետևաբար, անհնար է ազդել պատահական թվի առաջացման վրա։ Որոշակի միջակայքում թիվ ստանալու համար (օրինակ՝ 1-ից 100), օգտագործեք toInt փոխակերպման ֆունկցիան և %100 (նման ՊՆ).

Հոդվածի սկզբում մենք նշեցինք գործառույթը rsaVerify (), որը թույլ է տալիս ստուգել RSA ստորագրության վավերականությունը՝ օգտագործելով մասնավոր բանալի ընդդեմ հանրայինի: Ահա GenerateRandInt(gameId,rsaSign) մասը.

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

RSAPUBLIC հանրային բանալին և rsaSign տողը փոխանցվում են մուտքագրմանը: Ստորագրությունը ստուգվում է վավերականության համար: Թիվը ստեղծվում է, եթե ստուգումը հաջող է: Հակառակ դեպքում համակարգը համարում է, որ ստորագրությունը վավեր չէ (Invalid RSA signature):

Սերվերը պետք է ստորագրի խաղի ID-ն անձնական բանալիով և ուղարկի վավեր Rsa ստորագրություն 2880 բլոկների ընթացքում: Պարամետրը կազմաձևվում է խելացի պայմանագիրը գործարկելիս: Եթե ​​սահմանված ժամկետում ոչինչ տեղի չունենա, օգտվողը հաղթում է: Այս դեպքում մրցանակը պետք է ինքներդ ուղարկվի ձեր հասցեով։ Ստացվում է, որ «սերվերի համար ձեռնտու չէ խաբել», քանի որ դա հանգեցնում է կորստի։ Ստորև բերված է օրինակ:

RSA պատահական բլոկչեյնի վրա

Օգտագործողը խաղում է Dice Roller. Ես ընտրել եմ խորանարդի 2 կողմերից 6-ը, խաղադրույքը 14 ԱԼԻՔ է: Եթե ​​սերվերը սահմանված ժամկետում (2880 բլոկ) խելացի պայմանագրին վավեր RSA ստորագրություն չուղարկի, օգտվողը կվերցնի 34.44 ալիքներ:

Խաղերում թվեր ստեղծելու համար մենք օգտագործում ենք oracle՝ արտաքին, ոչ բլոկչեյն համակարգ: Սերվերը կատարում է խաղի id-ի RSA ստորագրությունը: Խելացի պայմանագիրը ստուգում է ստորագրության վավերականությունը և որոշում հաղթողին։ Եթե ​​սերվերը ոչինչ չի ուղարկում, ապա օգտվողը ավտոմատ կերպով հաղթում է:

Սա ազնիվ սերնդի մեթոդ է, քանի որ մանիպուլյացիան տեխնիկապես անհնար է։ Բոլոր Tradisys խաղերն աշխատում են նկարագրված ալգորիթմի հիման վրա: Ահա թե ինչպես են աշխատում բլոկչեյն խաղերը։ Ամեն ինչ թափանցիկ է և ստուգելի։ Ոչ մի այլ բլոկչեյնում նման համակարգի անալոգներ չկան։ Սա արդար պատահականություն է:

Source: www.habr.com

Добавить комментарий