Provably Fair kodda nasıl uygulanır?
Oyunun tamamlandığını ve hash'i kaldırılmış sunucu seed'ine, istemci seed'ine ve nonce'a sahip olduğumuzu varsayalım; süreç şu şekilde işler.
Oyun sonuçlarını oluşturmak için üç ana adım gereklidir.
byteGenerator (Rastgele Bayt Oluşturma)
generateFloats (Baytları Float'a (basamaklara) Dönüştürme)
Float'tan oyun olaylarına (float'ları orijinal oyunlardaki gerçek olaylara dönüştürme)
Rastgele Bayt Olarak ByteGenerator Bayt Oluşturucu
Bu byteGenerator fonksiyon, rastgele bayt oluşturucu olarak çalışır.
Benzersiz clientSeed, serverSeed, nonceve cursor değerlerini, kriptografik HMAC_SHA256 fonksiyonunu kullanarak rastgele ve benzersiz bir SHA-256 hash'lenmiş değer oluşturmak için alır.
Oluşturulan SHA-256 değeri 32 bayt boyutundadır. Yeterince rastgele bir oyun sonucu ile hesaplama yoğunluğu arasında denge sağlamak için, 32 bayt, her oyun sonucunu oluşturmak üzere her biri 4 bayttan oluşan 8 bölüme ayrılır*.
Birden fazla 8 oyun sonucunun gerekli olduğu belirli oyunlarda cursorkullanılır. İmleç başlangıçta 0 değerindedir ve sonuç gereksinimini karşılamak için 1,2,3,4 değerine yükselir,
Birden fazla 8 rastgele sonuca ihtiyaç duymadığımız oyunlarda, imleç değeri artmaz.
*4 bayt veri, rastgelelik için yeterince geniş bir havuz olan 2^32 (4,294,967,296) olası sonuç sağlar.
function* byteGenerator({ serverSeed, clientSeed, nonce, cursor }: ByteGeneratorInterface) {
// Setup cursor variables let currentRound = Math.floor(cursor / 32);
let currentRoundCursor = cursor;
currentRoundCursor -= currentRound * 32;
// Generate outputs until cursor requirement fullfilled
while (true) {
// HMAC function used to output provided inputs into bytes
const hmac = crypto.createHmac('sha256', serverSeed);
hmac.update(`${clientSeed}:${nonce}:${currentRound}`);
const buffer = hmac.digest();
// Update curser for next iteration of loop
while (currentRoundCursor < 32) {
yield Number(buffer[currentRoundCursor]);
currentRoundCursor += 1;
}
currentRoundCursor = 0;
currentRound += 1;
}
}GenerateFloats Fonksiyonu: Baytları Float'a Dönüştürme
Bu fonksiyon, SHA-256 onaltılık değerini baytlardan float'lara dönüştürerek Oyun Olayları için sonraki hesaplamalarda kullanılmasını sağlar.
Aşağıda, bir SHA-256 onaltılık değerinin bayttan float'a nasıl dönüştürüldüğü gösterilmektedir. Nihai çıktı olan numArr, oyunun gerektirdiği tüm olası sonuçları içerir. Yalnızca 1 sonuç gerekiyorsa liste yalnızca bir değer içerir.
Döndürülen dizideki öğe sayısını count temsil ederse, 0-1 arasında sayılardan oluşan bir dizi döndürür.
Kod:
// Convert the hash output from the rng byteGenerator to floats
export function generateFloats({
serverSeed,
clientSeed,
nonce,
cursor,
count,
}: GenerateFloatsInterface) {
// Random number generator function
const rng = byteGenerator({ serverSeed, clientSeed, nonce, cursor });
// Declare bytes as empty array
const bytes = [];
// Populate bytes array with sets of 4 from RNG output
while (bytes.length < count * 4) {
bytes.push(rng.next().value!);
}
// Return bytes as floats using lodash reduce function
const numArr = chunk(bytes, 4).map(bytesChunk =>
bytesChunk.reduce((result, value, i) => {
const divider = 256 ** (i + 1);
const partialResult = value / divider;
return result + partialResult;
}, 0),
);
return numArr;
}
Tüm orijinal oyunlarımız hem ByteGenerator hem de GenerateFloats fonksiyonlarını 0 ile 1 arasında rastgele float'lar oluşturmak için kullanır. Ancak bu noktadan sonra, her oyun oluşturulan float'tan oyun olayını belirlemek için kendine özgü bir süreç izler.
Bu benzersiz süreç ayrıntılı olarak Oyun Olayları bölümünde açıklanacaktır.
Örnek Açıklama
Burada, girdilerin bir zar oyunu olayını oluşturmak için nasıl kullanıldığını açıklayacağız.
Input Values: Given some random input values
serverSeed, clientSeed, nonce, cursor
Step 1: byteGenerator creates a SHA-256 byte
"a3f4e0ac7c7e8e9b5f16106c6b1d14e87c2c5a8d59b1d1c6a0b5f3e5a7d4c9a8”
Step 2: 256 bytes is split into 8 equal set of 32 bytes
"a3f4e0ac”, “7c7e8e9b”, “5f16106c”, “6b1d14e8”,
“7c2c5a8d”, “59b1d1c6”, “a0b5f3e5”, “a7d4c9a8”
Step 3: Each set is broken down into 2 bytes each
(only first 2 sets is shown)
set 1: a3-f4-e0-ac
set 2: 7c-7e-8e-9b
......
Step 4: Each of the 2 bytes represent a number from 0 to 255
set 1: [163, 244, 224, 172]
set 2: [124, 126, 142, 155]
......
Step 5: Using the formula in the code to generate numArr
Float 1 = (163 / (256^1)) + (244 / (256^2)) + (224 / (256^3))
+ (172 / (256^4)) = 0.64045528601
Float 2 = (124 / (256^1)) + (126 / (256^2)) + (142 / (256^3))
+ (155 / (256^4)) = 0.48630610737 Float 3 ......
Step 6: Output the floats in a list
numArr = [0.64045528601, 0.48630610737, ...... ]
*** Game Event Generation ***
Step 7: The numArr output will be used to generate game events,
depending on the game requirement
Example 7: Using dice as an example.
The game event is generated using the first numArr value.
const resultValue = floats.map(val => Math.floor(floats * 10001) / 100);
resultValue = Math.floor(0.64045528601 * 10001) / 100
= 64.05
Not: Gerçekte, bir oyun aktif olduğunda sunucu seed'i hash'lenir; bu nedenle oyuncu ve operatör, oyun sırasında bu sürecin tekil çıktısını görüntüleyemez.
Oyun sırasında ve oyun sonrasında aynı algoritma ve fonksiyonlar kullanıldığından, kullanıcılar aynı girdilerle sonucu her zaman doğrulayabilir.
