# Provably-fair

[![Build Status](https://travis-ci.org/atmys/provably-fair.svg?branch=master)](https://travis-ci.org/atmys/provably-fair)
[![Coverage Status](https://coveralls.io/repos/github/atmys/provably-fair/badge.svg?branch=master)](https://coveralls.io/github/atmys/provably-fair?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/atmys/provably-fair/badge.svg?targetFile=package.json)](https://snyk.io/test/github/atmys/provably-fair?targetFile=package.json)
[![codebeat badge](https://codebeat.co/badges/f9b951c9-3326-4a08-94db-13bc5a76dc1d)](https://codebeat.co/projects/github-com-atmys-provably-fair-master)


Dead simple generator for provably fair gambling. Entirely callback, we need performance here.
Uses a new server seed on each bet to provide verification capabilty to the client right after he gets the result.

### Provably-fair logic

The idea is to generate a reproductible result that is defined in advance to prevent the server from cheating.
To achieve this, we must :
- create a server seed and pass the hash of that seed to the client before he gambles;
- receive a client seed generated by the client;
- concat the two seeds to get only one;
- create the bet result from a random generator seeded with our concatenated seed.
- send the result to client, along with the original server seed.

This way, the client will be able to :
- make sure the server seed we used to generate the result is indeed the one we sent him as a hash (he can hash it himself to compare);
- reproduce the same bet result by reproducing the whole process.

## Getting Started

### Install

```
npm i --save provably-fair
```

### API
- `generateServerSeedHash({ userId = 'none', expiresIn = 60 * 60 })` stores server seed with redis & returns the seed hash to pass to client.
- `createAndChallenge({ userId = 'none', expiresIn = 60 * 60, serverSeedHash, clientSeed, guess, customResult, customValidation }, callback)` creates a new bet and compares the result with the client guess, then deletes the server seed redis key to prevent reuse. Returns `(err, valid, bet)`; 
- `verify({ serverSeed, clientSeed, customResult }, callback)` returns serverSeedHash of provided serverSeed & reproduces bet result.

#### `require('provably-fair')(client)`
- Initialize provablyFair
- `client` **Required:** Redis client
#### `generateServerSeedHash(options)`
- `options <Object>` 
  - `userId` **Default:** none - unique client identifier
  - `expiresIn` **Default:** 60 * 60
- returns `hash` hash of the securely stored with Redis serverSeed.
#### `createAndChallenge(options, callback)`
- `options <Object>` 
  - `userId` **Default:** none - unique client identifier
  - `expiresIn` **Default:** 60 * 60
  - `serverSeedHash` **Required**
  - `clientSeed` **Required**
  - `guess` **Required**
  - `customResult` **Default:** `function(randomNumber) { return randomNumer }`
  - `customValidation` **Default:** `function(guess, result) { return guess === result }`
- `callback <Function>` returns `(err, valid, bet)`
  - `valid <Boolean>` whether or not captcha is solved
  - `bet <Object>`
    - `id` bet ID
    - `result` bet result
    - `serverSeed`
    - `clientSeed`

### Example : Gobelet game

The client must guess a number between 1 and 10. Test it on [RunKit](https://runkit.com/atmys/provably-fair).

```js
// Init
const redis = require('redis');
const client = redis.createClient();

const provablyFair = require('provably-fair')(client);

// default return randomNumber
const gobeletResult = function (randomNumber) {
  return Math.floor(randomNumber * 10) + 1;
};

// this is default
const gobeletValidation = function (guess, result) {
  return guess === result;
};

// Generate & send before client gambles;
const serverSeedHash = provablyFair.generateServerSeedHash();

// Retrieve the serverSeedHash & these values from the client :
const clientSeed = 'clientSeed';
const guess = 5;

// We create & challenge the bet
provablyFair.createAndChallenge({
  serverSeedHash,
  clientSeed,
  expiresIn: 60 * 60,
  guess,
  customResult: gobeletResult,
  customValidation: gobeletValidation
}, (err, valid, bet) => {
  // returns true if guess is correct
  // bet = { serverSeed, clientSeed, result } can be passed to the client
  // for verification (along with your customResult resolver)
});
```

### Todo

Client plugin for verification.
