So, after a few hours hacking, I'm happy to be able to report the following status:
Note: Please see the end of this post for 3 "Edit" points which were added after the initial post to clarify some potential issues.
1. Initial site loading - get serverseed
If player is 100% new, generate new serverseed hash. If played before, get the same "next serverseed hash" as before.
The last part is important (saving the serverseed hash), because otherwise MP could "refuse" a winning bet by faking a bad connection. If a player would F5 after that "bad connection on bet" and get a new hash, MP would have prevented losing a bet. So it's important to get the same hash. In theory the player cannot trust your site either (potentially you are colluding with MP), so ideally this will be saved locally (localStorage seems ideal).
I can see the hash in the "getInitSettings" request and also that the same hash is saved server-side. Ideally you can still improve this to save it locally too and for example verify the hash with the one you get by getInitSettings (if wrong: probably check if that local hash was already used? then show error if really wrong.)
A new server seed is requested through the MP API when a new account is created. This has worked this way since site launch (as otherwise we wouldn't be able to place bets against MP), so nothing has changed here. Please note, that a new server seed is (and was) *not* received from MP if a bet fails so the latest valid server seed remains the one which is being used.
Regardless of the above, I've added code to save the server seed to local storage. When the page is loaded, the local server seed is compared to the server seed in the user profile (from DB) and if they don't match, the user will get an alert.
The exception to this is if the local storage server seed is null (meaning that a user has not logged in since the new code is in effect or has wiped his local storage). If this happens, the system writes the server seed received from the DB to local storage for future verification.
2. Initial site loading - get clientseedCheck localStorage if there was a previous generated clientseed, if yes, use that. If no, generate a new one in browser with
proper random generator (not Math.random.)
The first part is for the same reason as "saving serverseed hash". Imagine if a player makes a big bet that would win, but MP fakes a bad connection. Your player will probably get an error "try again later" or something. Player F5-es, you generate new clientseed and he bets again. Bet succeeded and was a loss with this second clientseed. No one will ever noticed that the player was cheated, but in reality MP would have gotten a free re-try of that losing bet. From a player-perspective, they cannot trust you either (since you could also fake a bad connection.) That's why the clientseed should be saved locally like localStorage.
You generate the clientseed properly now with a cryptographically secure RNG, but don't save it. Client seed is now also saved to local storage and as such, will be re-used if a bet doesn't go through.
When a bet is placed, a new client seed is generated and sent along with the bet data and then saved to the user profile in the DB. If/When the bet is returned as successfully processed, the previously generated client seed is written to local storage for reuse and checking. This ensures that
a) Client seeds are available for checking and are continously updated as bets are placed
b) Client seeds are only updated if a bet is returned as successful, meaning that if a bet fails, the next roll will reuse the client seed of the failed bet.
3. Show the serverseed hash + clientseed
The app should show the serverseed hash + clientseed, so that a player can write it down.
Showing this hash and clientseed is crucial, because the player needs to verify the serverseed didn't change. If you only get the hash after the bet, it has no value.. because the site could just give u any losing seed+hash (that "verifies".) So basically, getting the serverseed hash before each bet is a crucial part of the provably fair mechanism. Obviously the player must see the clientseed too, even though you generate it fairly in the browser, because not everyone can check their HTTP requests and JS vars.
Ideally this will be a small "Provably fair" box on the site - potentially one that can be shown/hidden. Small detail: I think it's important for "per roll" implementations (like MP app) to ensure that no HTTP request was made when someone clicks on the "Provably fair" tab/box too (because it notifies the site when the player is actively checking their rolls.) Besides that you should already have the serverseed hash and clientseed, so no need to make a HTTP request.
Currently I cannot see where you show the serverseed hash + clientseed, you really must show this. That being said, for nerds like me, I can figure it out in the HTTP request and JS vars for the initial bet. But not everyone is a nerd like me.
I've added a box on the side (currently it's always visible, we'll see what our users say) where upon placement of the bet, the locally available info (client seed + server seed) are displayed right away. Once the bet returns as being successful, the display is updated with the info from the server (betID, server secret, salt, next server seed and the reported roll). Using this info, the system then re-calculates the bet result (on the client using a JS function) and displays this as "Verified result". If returned result and verified result match, these are marked in green. If not, they are marked in red.
This makes it easy to see:
1) The new server seed becoming the actually used server seed for the next bet
2) The verification of reported bet result against a locally computed one.
4. Allow player to change their clientseed
Okay, so now you generate the clientseed in a fair/secure way in the browser. In theory the player doesn't have to change their clientseed. That being said, not everyone has the technical knowledge to verify that the clientseed was indeed really generated in the browser. Potentially the clientseed was generated by "the gambling site" (in this case MP+BB) and since "the gambling site" also know the serverseed, they could make any outcome they want based on previous plays if they generate both seeds.
Again, I know this is technically incorrect.. because you generate that clientseed 100% fair. But for non-technical people who still want to fully ensure that their bets were made 100% fair, allowing them to change the clientseed is an easy way to ensure this. This adjusted clientseed will be only used for the next bet (and also saved locally like #2.)
You should still allow the player to change their clientseed even when you generate a new clientseed every roll.
Done. Player can set client seed and then the previously discussed local client seed generation resumes.
5. Player makes bet (sends bet details + clientseed) - gets result/seeds/secret + next serverseed hash
Okay, we made it.. time to make a bet. So the HTTP request to make a bet includes the clientseed since MP needs this to make the bet too. The HTTP response will have the bet result (roll/win/loss/profit/..?) But it should also include: the used serverseed (which is secret + salt) and the next serverseed hash.
The used serverseed is useful, because then you have all the components to calculate/verify the roll result in the browser. We will come back on this later at #7. Ideally you could show the previous secret, salt, hash, clientseed in that "Provably fair" box of #3 too, although they can be accessed through the bet detail popup too.
The next serverseed hash is also crucial. Like mentioned in the previous points, the player needs this hash before each bet to ensure the bets were made fair and the serverseed didn't change. So after this first bet, you will again need to show the serverseed hash for the next bet so the player can write this down and afterwards verify the hash didn't change. So this next serverseed hash should be shown.
Currently you do not return and show any of this information. Even nerds like me, cannot get the next serverseed hash after the first bet unless I click bet details of previous bet.
Done, see info from point #3.
6. Generate new clientseed
After the bet and after we got the next serverseed hash, we generate a new random clientseed in the browser.
You changed this in your last fix so this is good now. Although it must be still saved and shown like previous points.
Done, see info from point #2.
7. Verify the bet in browser
Like I said, the advantage of the MP provably fair mechanism is that you, as gambling site, can actively protect the player from MP cheating. To do this, you would need to automatically verify the bet after each bet was made. Since you have all the seeds/hash/profit, you can: 1) check hash 2) calculate outcome/roll and verify if same 3) verify if profit/loss is correct. This should be all done in the browser. Give error if not fully verified.
Note that most gambling sites do not do this. Verifying is all about not having to trust the gambling site and checking if they calculated the results fair. But if you use a site to verify, you are trusting that specific site to properly verify it. So in theory, if the gambling site cheats the player, their own verifier will probably say it was all fair too. That's why I think third-party verifiers are much better and basically on-site verifiers doesn't make much sense ... for non-MP sites.
However, for MP sites, it makes perfect sense. Because in this case, the MP app is the third-party verifier since it is checking the results coming from MP. This way you can actively protect the players against potential MP cheating. So from a provably fair perspective I see this as an advantage of MP (apps) compared to non-MP apps. Obviously this advantage is only used if you actually do this.
Ideally you will verify each bet in the browser.
Done. See info from point #2.
8. Make it easy for players to verify the bets on a third-party verifierThere is this great site called dicesites.com that has verifiers for a lot of sites and allows URL parameters (seeds,hashes,etc) to easily verify bets with
a single click. This makes it easier for players to verify their bets on a third-party.
You guys do this I still need to a link to the newly added sidebar bet info box to allow this, but for now I think we're OK (you can always click on the bet link and use the link from the popup/modal which displays).
000. Small things
Some smaller things: you should just delete the "Client Seed Sequence" reference now, it's only confusing and never used.
Done.
Sometimes you show a negative value at "Server Secret" when the results gets over 2^32-1 (SQL INT limit?) This causes the "result" verification to be correct but the "hash" not. Example:
MP says secret is 3,990,879,637. You say that secret is -304,087,659 for that bet. With clientseed 335,767,772... the outcome will be both 31,680,113 because (3990879637+335767772)%2^32 = (-304087659+335767772)%2^32 - but the hash will be different.
Verifier linked from your site.
Should also be fixed.
In closing: thank you for your help. I think/hope that we now got it right and that we have an unassailable provably fair system. I would appreciate if if you could:
1) Comment on my replies to your points and see if everything sounds OK.
2) Give my JS code another look to see if it all holds up.
Hopefully all is OK and we can now put this thing to rest.
EDIT: if you're getting a semi-broken layout when going to our site, please press CTRL-Reload to force your browser to reload the new CSS file.
EDIT2: Turns out on Firefox there's a difference in the way a certain CSS command is implemented leading to a text overflow on the provably fair box. I'll try to find a way around it but our strong recommendation is to use Chrome, it's simply a better browser.
EDIT3: One of our users has reported a "Server Seed mismatch" error the first time he visits the site after this update. I can't reproduce it so far but I'll try to figure out why.