var express = require("@runkit/runkit/express-endpoint/1.0.0");
var app = express(exports);
const sha256 = require("simple-sha256")
const crypto = require('crypto')
const _ = require('lodash')
const multipliers = [2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10];
const tiles = {
normal: ['2x', '3x', '5x', '10x'],
bonus: ['hunt', 'plinko', 'coinflip', 'rustytime']
}
const wheel = ['2x', '5x', '2x', '3x', 'coinflip', '2x', '3x', '5x', '2x', '3x', '2x', 'plinko', '2x', '5x', '3x', '10x', '2x', '3x', '2x', 'rustytime', '2x', '3x', '5x', '2x', 'coinflip', '2x', '3x', '10x', '5x', '2x', 'hunt', '2x', '5x', '3x', '2x', 'plinko', '3x', '2x', '10x', '3x']
const gamemodes = {
coinflip: [
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9,
9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15,
15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25,
26, 27, 28, 29, 30
],
hunt: [
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 40, 40, 40, 40, 40, 40, 40, 50, 50, 50, 50, 50, 50, 50, 75, 75, 75, 75, 100, 200
],
plinko: [
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 25, 25, 25, 25, 25, 40, 40, 40, 50, 50, 100
],
rustytime: [
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
20, 20, 20, 20, 20, 20, 30, 30, 30, 40, 40, 50, 50, 100, 200
]
};
let private_seed_hash = ''
let private_seed = ''
let round_id = ''
async function getResult() {
let multiplier = getMultiplierResult()
let main = getMainResult()
let bonus = tiles.bonus.includes(main.tile) ? getBonusResult(main.tile) : {}
return {seed: await sha256(private_seed) === private_seed_hash, multiplier, main, bonus }
}
function getMultiplierResult() {
let multiplier_seed = private_seed + '-' + round_id + '-multiplier'
let hmac_multiplier = crypto.createHmac('SHA512', multiplier_seed)
let buf_multiplier = hmac_multiplier.digest()
let multiplierTicket = buf_multiplier.readUInt32BE() / Math.pow(2, 32)
let multiplier = { won: multiplierTicket < 1 / 3, ticket: multiplierTicket }
if (multiplierTicket < 1 / 3) {
let hmac_tile = crypto.createHmac('SHA512', multiplier_seed + '-tile')
let hmac_value = crypto.createHmac('SHA512', multiplier_seed + '-value')
let buf_tile = hmac_tile.digest()
let buf_value = hmac_value.digest()
let tile_ticket = buf_tile.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let value_ticket = buf_value.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let tileIndex = _.floor(tile_ticket * (tiles.normal.length + tiles.bonus.length), 0)
multiplier.tile = tileIndex < tiles.normal.length
? tiles.normal[tileIndex]
: tiles.bonus[tileIndex - tiles.normal.length]
multiplier.value = multipliers[_.floor(value_ticket * multipliers.length, 0)]
}
return multiplier
}
function getMainResult() {
let hmac_main = crypto.createHmac('SHA512', private_seed + '-' + round_id)
let buf_main = hmac_main.digest()
let winning_ticket = buf_main.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let winning_tile = wheel[_.floor(winning_ticket * wheel.length, 0)]
return {ticket: winning_ticket, tile: winning_tile}
}
function getBonusResult(type) {
let bonus = {type, data: {}}
let bonus_seed = private_seed + '-' + round_id + '-' + type
let hmac_bonus = crypto.createHmac('SHA512', bonus_seed)
let buf_bonus = hmac_bonus.digest()
bonus.data.ticket = buf_bonus.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
if (type === 'coinflip') {
let hmac_red = crypto.createHmac('SHA512', bonus_seed + '-red')
let hmac_blue = crypto.createHmac('SHA512', bonus_seed + '-blue')
let red_ticket = hmac_red.digest().readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let blue_ticket = hmac_blue.digest().readUInt32BE() / Math.pow(2, 32) - 0.0000000001
bonus.data.red_coin = gamemodes.coinflip[_.floor(red_ticket * gamemodes.coinflip.length, 0)]
bonus.data.blue_coin = gamemodes.coinflip[_.floor(blue_ticket * gamemodes.coinflip.length, 0)]
bonus.data.winning_coin = bonus.data.ticket < 0.5 ? 'red' : 'blue'
}
if (type === 'plinko') {
bonus.data.multipliers = []
for (let i = 0; i < 13; i++) {
let hmac_plinko = crypto.createHmac('SHA512', bonus_seed + '-' + i)
let buf_plinko = hmac_plinko.digest()
let multiplier_ticket = buf_plinko.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let multiplier = gamemodes.plinko[_.floor(multiplier_ticket * gamemodes.plinko.length, 0)]
bonus.data.multipliers.push(multiplier)
}
bonus.data.winning_multiplier =
bonus.data.multipliers[_.floor(bonus.data.ticket * bonus.data.multipliers.length, 0)]
}
if (type === 'hunt') {
bonus.data.board = []
bonus.data.picks = {}
for (let i = 0; i < 90; i++) {
let hmac_board = crypto.createHmac('SHA512', bonus_seed + '-' + i)
let buf_board = hmac_board.digest()
let board_ticket = buf_board.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let multiplier = gamemodes.hunt[_.floor(board_ticket * gamemodes.hunt.length, 0)]
bonus.data.board.push(multiplier)
}
}
if (type === 'rustytime') {
bonus.data.wheel = []
for (let i = 0; i < 40; i++) {
let hmac_tile = crypto.createHmac('SHA512', bonus_seed + '-' + i)
let buf_tile = hmac_tile.digest()
let tile_ticket = buf_tile.readUInt32BE() / Math.pow(2, 32) - 0.0000000001
let multiplier = gamemodes.rustytime[_.floor(tile_ticket * gamemodes.rustytime.length, 0)]
bonus.data.wheel.push(multiplier)
}
bonus.data.winning_tile = bonus.data.wheel[_.floor(bonus.data.ticket * bonus.data.wheel.length, 0)]
}
return bonus
}
const result = await getResult()
if (result.seed) {
console.log(result)
} else {
console.log("Private seed hash doesn't match private seed")
}
// ENDPOINT CODE - IRRELEVANT FOR IN-CODE VERIFICATION
app.get("/", async (req, res) => {
private_seed_hash = req.query.private_seed_hash
private_seed = req.query.private_seed
round_id = req.query.round_id
if (_.isNil(private_seed) || _.isNil(private_seed_hash) || _.isNil(round_id))
res.send("Missing parameters!")
const result = await getResult()
let html = `<body style="margin: 0"><div style="display: flex; align-items: center; justify-content: center; flex-direction: column; width: 100%; height: 100%; background: #1E242B;">`
html += result.seed
? `<img src="https://img.icons8.com/color/344/checked.png" style="height: 75px;width: 75px;">`
: `<img src="https://img.icons8.com/color/344/cancel.png" style="height: 75px;width: 75px;">`
let mainHTML = ''
_.forIn(result.main, (value, key) => {
mainHTML += `<h3 style="margin: 0; color: #3492ff">${_.capitalize(key)}: ${value}</h3>`
})
let multiplierHTML = ''
_.forIn(result.multiplier, (value, key) => {
multiplierHTML += `<h3 style="margin: 0; color: #3492ff">${_.capitalize(key)}: ${value}</h3>`
})
let bonusHTML = ''
if (!_.isEmpty(result.bonus)) bonusHTML += `<h2 style="margin: 0; color: white">Bonus:</h2>`
_.forIn(result.bonus, (value, key) => {
if (_.isObject(value)) {
_.forIn(value, (v, k) => {
bonusHTML += `<h4 style="margin: 0; color: #C8E6C9">${_.capitalize(k)}: ${v}</h4>`
})
}
else bonusHTML += `<h3 style="margin: 0; color: #3492ff">${_.capitalize(key)}: ${value}</h3>`
})
html += result.seed
? `<h2 style="margin: 0; color: white">Result:</h2>
${mainHTML}
<h2 style="margin: 0; color: white">Multiplier:</h2>
${multiplierHTML}
${bonusHTML}`
: `<h3 style="margin: 0; color: white">Private seed hash doesn't match private seed</h3>`
res.send(html)
})