Baccarat seed event
Starting with a secret I've generated a chain of 10,000,000 SHA256 hashes. Each element is the hash of the lowercase, hexadecimal string representation of the previous hash. The hash of the chain's last element is
3aa3ac48f926071d6969702dbd7c3c0a85faf498f8a6081866ef4cf12d428c96 .
Every game maps to a hash in the chain: The 10,000,000th element of the chain is the hash of game #1 and the first element in the chain is the hash of game #10,000,000. To verify that a hash belongs to a game #n, simply hash it n times and compare the result with the terminating hash.
To calculate a game's result from its hash:
const CryptoJS = require("crypto-js");
function seedGenerator(hash, salt) {
const hmac = CryptoJS.HmacSHA256(CryptoJS.enc.Hex.parse(hash), salt);
return hmac.toString(CryptoJS.enc.Hex);
}
function createNums(allNums, hash) {
const nums = [];
let h = CryptoJS.SHA256(hash).toString(CryptoJS.enc.Hex);
allNums.forEach((c) => {
nums.push({ num: c, hash: h });
h = h.substring(1) + h.charAt(0);
});
nums.sort(function (o1, o2) {
if (o1.hash < o2.hash) {
return -1;
} else if (o1.hash === o2.hash) {
return 0;
} else {
return 1;
}
});
return nums;
}
function getTotalPoint(points) {
let count = 0;
points.forEach((point) => {
let _point = point & 0xf;
count += _point >= 10 ? 0 : _point;
});
return count % 10;
}
function playing(allCards, startIndex) {
const playerCards = [allCards[startIndex], allCards[startIndex + 2]];
const bankerCards = [allCards[startIndex + 1], allCards[startIndex + 3]];
const playerTotalPoint = getTotalPoint(playerCards);
const bankerTotalPoint = getTotalPoint(bankerCards);
const lastCard = allCards[startIndex + 5];
const getLastPoint = function (cards) {
return getTotalPoint([cards[2]]);
};
if (bankerTotalPoint >= 8 || playerTotalPoint >= 8) {
// get result
} else if (playerTotalPoint >= 6 && bankerTotalPoint >= 6) {
// get result
} else {
if (playerTotalPoint <= 5) {
playerCards.push(allCards[startIndex + 4]);
}
if (playerCards.length == 2) {
if (bankerTotalPoint <= 5) {
bankerCards.push(allCards[startIndex + 4]);
}
} else if (bankerTotalPoint <= 2) {
bankerCards.push(lastCard);
} else if (
bankerTotalPoint == 3 &&
playerCards.length == 3 &&
getLastPoint(playerCards) != 8
) {
bankerCards.push(lastCard);
} else if (
bankerTotalPoint == 4 &&
playerCards.length == 3 &&
getLastPoint(playerCards) >= 2 &&
getLastPoint(playerCards) <= 7
) {
bankerCards.push(lastCard);
} else if (
bankerTotalPoint == 5 &&
playerCards.length == 3 &&
getLastPoint(playerCards) >= 4 &&
getLastPoint(playerCards) <= 7
) {
bankerCards.push(lastCard);
} else if (
bankerTotalPoint == 6 &&
playerCards.length == 3 &&
getLastPoint(playerCards) >= 6 &&
getLastPoint(playerCards) <= 7
) {
bankerCards.push(lastCard);
}
}
let result = {
player: {
points: playerCards.map((card) => createCardFram(card)),
totalPoint: getTotalPoint(playerCards),
},
banker: {
points: bankerCards.map((card) => createCardFram(card)),
totalPoint: getTotalPoint(bankerCards),
},
};
return result;
}
function getAllCards(hash, salt) {
const allNums = [
161,
180,
199,
218,
162,
205,
181,
200,
219,
163,
182,
220,
201,
177,
196,
215,
170,
178,
221,
197,
216,
171,
179,
198,
172,
217,
193,
212,
167,
186,
194,
173,
213,
168,
187,
195,
214,
188,
169,
209,
164,
183,
202,
210,
189,
165,
184,
203,
211,
166,
204,
185,
];
let seed = seedGenerator(hash, salt);
let finalNums = createNums(allNums, seed);
seed = String(CryptoJS.SHA256(seed));
finalNums = createNums(finalNums, seed);
let allCards = finalNums
.slice(0, 6)
.map((m) => m.num)
.map((item) => item.num);
return allCards;
}
function createCardFram(card) {
const CARDS = " ,A,2,3,4,5,6,7,8,9,10,J,Q,K".split(",");
const SUITS = ["♠️", "♥️", "♣️", "♦️"];
let suitsIndex = (card & 240) / 16 - 10;
let suits = SUITS[suitsIndex];
let point = CARDS[card % 16];
let color = suitsIndex % 2 === 0 ? "black" : "red";
return {
color,
suits,
point,
};
}
function verifyBaccarat(seed, salt) {
let allCards = getAllCards(seed, salt);
let result = playing(allCards, 0);
console.log(Seed: ${seed} Salt: ${salt});
console.log(Banker points: ${result.banker.totalPoint} cards: ${result.banker.points.map(m => { return m.color + m.suits + m.point; })});
console.log(Player points: ${result.player.totalPoint} cards: ${result.player.points.map(m => { return m.color + m.suits + m.point; })});
console.log("")
return result;
}
// entry
verifyBaccarat("GAME_HASH", "SALT");
Before being used to calculate the corresponding result, each game hash is salted with the lowercase, hexadecimal string representation of the hash of bitcoin block
654,460 .
This block has not been mined yet at the time of starting the provably fair seeding event, proving that I have not deliberately picked a chain that is unfavorable for players.