@casino-core/probably-fair 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/dist/block-fetchers/bsc.d.ts +12 -0
- package/dist/block-fetchers/bsc.d.ts.map +1 -0
- package/dist/block-fetchers/bsc.js +33 -0
- package/dist/block-fetchers/bsc.js.map +1 -0
- package/dist/block-fetchers/eos.d.ts +13 -0
- package/dist/block-fetchers/eos.d.ts.map +1 -0
- package/dist/block-fetchers/eos.js +28 -0
- package/dist/block-fetchers/eos.js.map +1 -0
- package/dist/block-fetchers/index.d.ts +5 -0
- package/dist/block-fetchers/index.d.ts.map +1 -0
- package/dist/block-fetchers/index.js +8 -0
- package/dist/block-fetchers/index.js.map +1 -0
- package/dist/crypto.d.ts +17 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +38 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/nonce.d.ts +7 -0
- package/dist/nonce.d.ts.map +1 -0
- package/dist/nonce.js +22 -0
- package/dist/nonce.js.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +11 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +64 -0
- package/dist/verify.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# probably-fair
|
|
2
|
+
|
|
3
|
+
Provably fair gaming module for casino platforms. Shared NPM package for server seed, client seed, nonce (custom, EOS block height, or BSC block height), deterministic random number generation, and verification.
|
|
4
|
+
|
|
5
|
+
**Important:** Never log or expose the server seed. Only its hash is shown before the round; the seed is revealed after settlement for verification.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install probably-fair
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Algorithm (summary)
|
|
14
|
+
|
|
15
|
+
1. **Commit:** Before the round, show `getServerSeedHash(serverSeed)` to the user.
|
|
16
|
+
2. **Message:** HMAC-SHA256 uses server seed as key and `clientSeed:nonce[:A:B:...]` as message (optional extra params A, B, …).
|
|
17
|
+
3. **Result:** The 32-byte HMAC is converted to float(s) in [0,1] and optionally scaled to a range (e.g. dice 1–6).
|
|
18
|
+
4. **Verify:** After the round, reveal the server seed; the user checks that `hash(serverSeed)` equals the committed hash and that recomputing with the same client seed, nonce, and extra params yields the same result.
|
|
19
|
+
|
|
20
|
+
## API
|
|
21
|
+
|
|
22
|
+
### Core (no network)
|
|
23
|
+
|
|
24
|
+
- **`getServerSeedHash(serverSeed: string): string`**
|
|
25
|
+
Returns SHA-256 hash of the server seed (pre-commitment).
|
|
26
|
+
|
|
27
|
+
- **`getClientSeed(): string`**
|
|
28
|
+
Returns the current client seed from the optional in-memory store.
|
|
29
|
+
|
|
30
|
+
- **`setClientSeed(seed: string): void`**
|
|
31
|
+
Sets the client seed in the optional in-memory store. You can also pass the client seed explicitly into other functions.
|
|
32
|
+
|
|
33
|
+
- **`getNonce(options: NonceSource): number`**
|
|
34
|
+
Returns the numeric nonce. Options:
|
|
35
|
+
- `{ type: 'custom', value: number }`
|
|
36
|
+
- `{ type: 'eos', blockHeight: number }`
|
|
37
|
+
- `{ type: 'bsc', blockHeight: number }`
|
|
38
|
+
|
|
39
|
+
- **`generateRandomNumber(serverSeed, clientSeed, nonce, extraParams?, options?): number | number[]`**
|
|
40
|
+
Deterministic random number(s).
|
|
41
|
+
- `nonce`: `NonceSource` object or a number.
|
|
42
|
+
- `extraParams`: optional `[A, B, ...]` (string or number) included in the HMAC message so the result is bound to these parameters.
|
|
43
|
+
- `options`: optional `{ min, max, count, integer }` to scale and shape the output (defaults: one float in [0,1]).
|
|
44
|
+
|
|
45
|
+
- **`verifyFairness(serverSeed, clientSeed, nonce, committedServerSeedHash, expectedResult, extraParams?, options?): VerifyResult`**
|
|
46
|
+
Recomputes the result and checks that the server seed hash matches.
|
|
47
|
+
Pass the same `extraParams` and `options` you used when generating the result.
|
|
48
|
+
|
|
49
|
+
### Optional block fetchers (network)
|
|
50
|
+
|
|
51
|
+
Use when the nonce is EOS or BSC block height and you want to fetch it from RPC:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import { getEosBlockHeight, getBscBlockHeight } from 'probably-fair/block-fetchers';
|
|
55
|
+
|
|
56
|
+
const eosBlock = await getEosBlockHeight(); // default RPC or pass URL
|
|
57
|
+
const bscBlock = await getBscBlockHeight();
|
|
58
|
+
// Then: getNonce({ type: 'eos', blockHeight: eosBlock }) or type: 'bsc', blockHeight: bscBlock
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You can also obtain block height from your own backend and pass it into `getNonce` without using these fetchers.
|
|
62
|
+
|
|
63
|
+
## Usage examples
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
const {
|
|
67
|
+
getServerSeedHash,
|
|
68
|
+
setClientSeed,
|
|
69
|
+
getNonce,
|
|
70
|
+
generateRandomNumber,
|
|
71
|
+
verifyFairness,
|
|
72
|
+
} = require('probably-fair');
|
|
73
|
+
|
|
74
|
+
const serverSeed = 'my-secret-server-seed';
|
|
75
|
+
const clientSeed = 'user-client-seed';
|
|
76
|
+
const nonce = getNonce({ type: 'custom', value: 0 });
|
|
77
|
+
|
|
78
|
+
// Before round: show only the hash
|
|
79
|
+
const committedHash = getServerSeedHash(serverSeed);
|
|
80
|
+
|
|
81
|
+
// Generate result (e.g. dice 1–6)
|
|
82
|
+
const roll = generateRandomNumber(serverSeed, clientSeed, nonce, undefined, {
|
|
83
|
+
min: 1,
|
|
84
|
+
max: 6,
|
|
85
|
+
integer: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// With extra parameters [A, B, ...]
|
|
89
|
+
const custom = generateRandomNumber(serverSeed, clientSeed, nonce, [10, 20], {
|
|
90
|
+
min: 0,
|
|
91
|
+
max: 99,
|
|
92
|
+
integer: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// After round: verify
|
|
96
|
+
const verification = verifyFairness(
|
|
97
|
+
serverSeed,
|
|
98
|
+
clientSeed,
|
|
99
|
+
nonce,
|
|
100
|
+
committedHash,
|
|
101
|
+
roll
|
|
102
|
+
);
|
|
103
|
+
console.log(verification.isFair); // true
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Types
|
|
107
|
+
|
|
108
|
+
- **`NonceSource`** – `{ type: 'custom', value } | { type: 'eos', blockHeight } | { type: 'bsc', blockHeight }`
|
|
109
|
+
- **`VerifyResult`** – `{ resultMatches, serverSeedHashMatches, isFair, computedResult? }`
|
|
110
|
+
- **`RandomNumberOptions`** – `{ min?, max?, count?, integer? }`
|
|
111
|
+
|
|
112
|
+
## Tests
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm test
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional BSC block height fetcher. Use when nonce type is BSC block height.
|
|
3
|
+
* Requires fetch (Node 18+ or browser).
|
|
4
|
+
*/
|
|
5
|
+
export interface BscBlockNumberResponse {
|
|
6
|
+
result?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Fetch current BSC block number from RPC. Use this value as nonce (e.g. getNonce({ type: 'bsc', blockHeight })).
|
|
10
|
+
*/
|
|
11
|
+
export declare function getBscBlockHeight(rpcUrl?: string): Promise<number>;
|
|
12
|
+
//# sourceMappingURL=bsc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsc.d.ts","sourceRoot":"","sources":["../../src/block-fetchers/bsc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,GAAE,MAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Optional BSC block height fetcher. Use when nonce type is BSC block height.
|
|
4
|
+
* Requires fetch (Node 18+ or browser).
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getBscBlockHeight = getBscBlockHeight;
|
|
8
|
+
const DEFAULT_BSC_RPC = "https://bsc-dataseed.binance.org/";
|
|
9
|
+
/**
|
|
10
|
+
* Fetch current BSC block number from RPC. Use this value as nonce (e.g. getNonce({ type: 'bsc', blockHeight })).
|
|
11
|
+
*/
|
|
12
|
+
async function getBscBlockHeight(rpcUrl = DEFAULT_BSC_RPC) {
|
|
13
|
+
const res = await fetch(rpcUrl, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
jsonrpc: "2.0",
|
|
18
|
+
method: "eth_blockNumber",
|
|
19
|
+
params: [],
|
|
20
|
+
id: 1,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(`BSC RPC error: ${res.status} ${res.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
const data = (await res.json());
|
|
27
|
+
const hex = data.result;
|
|
28
|
+
if (typeof hex !== "string") {
|
|
29
|
+
throw new Error("BSC eth_blockNumber did not return result");
|
|
30
|
+
}
|
|
31
|
+
return parseInt(hex, 16);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=bsc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsc.js","sourceRoot":"","sources":["../../src/block-fetchers/bsc.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAWH,8CAsBC;AA/BD,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAM5D;;GAEG;AACI,KAAK,UAAU,iBAAiB,CACrC,SAAiB,eAAe;IAEhC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QAC9B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,iBAAiB;YACzB,MAAM,EAAE,EAAE;YACV,EAAE,EAAE,CAAC;SACN,CAAC;KACH,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA2B,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;IACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional EOS block height fetcher. Use when nonce type is EOS block height.
|
|
3
|
+
* Requires fetch (Node 18+ or browser).
|
|
4
|
+
*/
|
|
5
|
+
export interface EosGetInfoResponse {
|
|
6
|
+
head_block_num?: number;
|
|
7
|
+
last_irreversible_block_num?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fetch current EOS block height from RPC. Use this value as nonce (e.g. getNonce({ type: 'eos', blockHeight })).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getEosBlockHeight(rpcUrl?: string): Promise<number>;
|
|
13
|
+
//# sourceMappingURL=eos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eos.d.ts","sourceRoot":"","sources":["../../src/block-fetchers/eos.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,GAAE,MAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Optional EOS block height fetcher. Use when nonce type is EOS block height.
|
|
4
|
+
* Requires fetch (Node 18+ or browser).
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getEosBlockHeight = getEosBlockHeight;
|
|
8
|
+
const DEFAULT_EOS_RPC = "https://eos.greymass.com/v1/chain/get_info";
|
|
9
|
+
/**
|
|
10
|
+
* Fetch current EOS block height from RPC. Use this value as nonce (e.g. getNonce({ type: 'eos', blockHeight })).
|
|
11
|
+
*/
|
|
12
|
+
async function getEosBlockHeight(rpcUrl = DEFAULT_EOS_RPC) {
|
|
13
|
+
const res = await fetch(rpcUrl, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify({}),
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
throw new Error(`EOS RPC error: ${res.status} ${res.statusText}`);
|
|
20
|
+
}
|
|
21
|
+
const data = (await res.json());
|
|
22
|
+
const blockNum = data.head_block_num ?? data.last_irreversible_block_num;
|
|
23
|
+
if (typeof blockNum !== "number") {
|
|
24
|
+
throw new Error("EOS get_info did not return block number");
|
|
25
|
+
}
|
|
26
|
+
return blockNum;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=eos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eos.js","sourceRoot":"","sources":["../../src/block-fetchers/eos.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAYH,8CAiBC;AA3BD,MAAM,eAAe,GAAG,4CAA4C,CAAC;AAOrE;;GAEG;AACI,KAAK,UAAU,iBAAiB,CACrC,SAAiB,eAAe;IAEhC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QAC9B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuB,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,2BAA2B,CAAC;IACzE,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/block-fetchers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,YAAY,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBscBlockHeight = exports.getEosBlockHeight = void 0;
|
|
4
|
+
var eos_1 = require("./eos");
|
|
5
|
+
Object.defineProperty(exports, "getEosBlockHeight", { enumerable: true, get: function () { return eos_1.getEosBlockHeight; } });
|
|
6
|
+
var bsc_1 = require("./bsc");
|
|
7
|
+
Object.defineProperty(exports, "getBscBlockHeight", { enumerable: true, get: function () { return bsc_1.getBscBlockHeight; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/block-fetchers/index.ts"],"names":[],"mappings":";;;AAAA,6BAA0C;AAAjC,wGAAA,iBAAiB,OAAA;AAE1B,6BAA0C;AAAjC,wGAAA,iBAAiB,OAAA"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-256 hash of the server seed (for pre-commitment).
|
|
3
|
+
*/
|
|
4
|
+
export declare function sha256Hex(input: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* HMAC-SHA256 with server seed as key and message as data.
|
|
7
|
+
*/
|
|
8
|
+
export declare function hmacSha256Hex(key: string, message: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* HMAC-SHA256 raw bytes (32 bytes).
|
|
11
|
+
*/
|
|
12
|
+
export declare function hmacSha256Bytes(key: string, message: string): Buffer;
|
|
13
|
+
/**
|
|
14
|
+
* Convert 32 bytes to floats in [0, 1] by taking 4-byte chunks (big-endian) and dividing by 2^32.
|
|
15
|
+
*/
|
|
16
|
+
export declare function bytesToFloats(bytes: Buffer, count: number): number[];
|
|
17
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAOpE"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sha256Hex = sha256Hex;
|
|
4
|
+
exports.hmacSha256Hex = hmacSha256Hex;
|
|
5
|
+
exports.hmacSha256Bytes = hmacSha256Bytes;
|
|
6
|
+
exports.bytesToFloats = bytesToFloats;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const ENCODING = "hex";
|
|
9
|
+
/**
|
|
10
|
+
* SHA-256 hash of the server seed (for pre-commitment).
|
|
11
|
+
*/
|
|
12
|
+
function sha256Hex(input) {
|
|
13
|
+
return (0, crypto_1.createHash)("sha256").update(input, "utf8").digest(ENCODING);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* HMAC-SHA256 with server seed as key and message as data.
|
|
17
|
+
*/
|
|
18
|
+
function hmacSha256Hex(key, message) {
|
|
19
|
+
return (0, crypto_1.createHmac)("sha256", key).update(message, "utf8").digest(ENCODING);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* HMAC-SHA256 raw bytes (32 bytes).
|
|
23
|
+
*/
|
|
24
|
+
function hmacSha256Bytes(key, message) {
|
|
25
|
+
return (0, crypto_1.createHmac)("sha256", key).update(message, "utf8").digest();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert 32 bytes to floats in [0, 1] by taking 4-byte chunks (big-endian) and dividing by 2^32.
|
|
29
|
+
*/
|
|
30
|
+
function bytesToFloats(bytes, count) {
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = 0; i < count && i * 4 + 4 <= bytes.length; i++) {
|
|
33
|
+
const uint = bytes.readUInt32BE(i * 4);
|
|
34
|
+
out.push(uint / 4294967296);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":";;AAOA,8BAEC;AAKD,sCAEC;AAKD,0CAEC;AAKD,sCAOC;AAnCD,mCAAgD;AAEhD,MAAM,QAAQ,GAAG,KAAc,CAAC;AAEhC;;GAEG;AACH,SAAgB,SAAS,CAAC,KAAa;IACrC,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,GAAW,EAAE,OAAe;IACxD,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,GAAW,EAAE,OAAe;IAC1D,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,KAAa,EAAE,KAAa;IACxD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,UAAa,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { NonceSource, VerifyResult, RandomNumberOptions } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Returns SHA-256 hash of the server seed (pre-commitment shown to user before round).
|
|
4
|
+
*/
|
|
5
|
+
export declare function getServerSeedHash(serverSeed: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get the current client seed (from optional in-memory store).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getClientSeed(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Set the client seed (optional in-memory store). Platforms can also pass client seed per call.
|
|
12
|
+
*/
|
|
13
|
+
export declare function setClientSeed(seed: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Return the numeric nonce from the given nonce source (custom, EOS block height, or BSC block height).
|
|
16
|
+
*/
|
|
17
|
+
export declare function getNonce(options: NonceSource): number;
|
|
18
|
+
/**
|
|
19
|
+
* Generate deterministic random number(s). Optional extraParams [A, B, ...] are included in the HMAC message.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateRandomNumber(serverSeed: string, clientSeed: string, nonce: NonceSource | number, extraParams?: (string | number)[], options?: RandomNumberOptions): number | number[];
|
|
22
|
+
/**
|
|
23
|
+
* Verify fairness: recompute result and check server seed hash.
|
|
24
|
+
*/
|
|
25
|
+
export declare function verifyFairness(serverSeed: string, clientSeed: string, nonce: NonceSource | number, committedServerSeedHash: string, expectedResult: number | number[], extraParams?: (string | number)[], options?: RandomNumberOptions): VerifyResult;
|
|
26
|
+
export type { NonceSource, VerifyResult, RandomNumberOptions };
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAK9E;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACjC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,GAAG,MAAM,EAAE,CAQnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,uBAAuB,EAAE,MAAM,EAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,EACjC,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACjC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CAUd;AAED,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getServerSeedHash = getServerSeedHash;
|
|
4
|
+
exports.getClientSeed = getClientSeed;
|
|
5
|
+
exports.setClientSeed = setClientSeed;
|
|
6
|
+
exports.getNonce = getNonce;
|
|
7
|
+
exports.generateRandomNumber = generateRandomNumber;
|
|
8
|
+
exports.verifyFairness = verifyFairness;
|
|
9
|
+
const crypto_1 = require("./crypto");
|
|
10
|
+
const nonce_1 = require("./nonce");
|
|
11
|
+
const verify_1 = require("./verify");
|
|
12
|
+
/** In-memory client seed for getClientSeed/setClientSeed (optional convenience). */
|
|
13
|
+
let clientSeedStore = "";
|
|
14
|
+
/**
|
|
15
|
+
* Returns SHA-256 hash of the server seed (pre-commitment shown to user before round).
|
|
16
|
+
*/
|
|
17
|
+
function getServerSeedHash(serverSeed) {
|
|
18
|
+
return (0, crypto_1.sha256Hex)(serverSeed);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the current client seed (from optional in-memory store).
|
|
22
|
+
*/
|
|
23
|
+
function getClientSeed() {
|
|
24
|
+
return clientSeedStore;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Set the client seed (optional in-memory store). Platforms can also pass client seed per call.
|
|
28
|
+
*/
|
|
29
|
+
function setClientSeed(seed) {
|
|
30
|
+
clientSeedStore = seed;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Return the numeric nonce from the given nonce source (custom, EOS block height, or BSC block height).
|
|
34
|
+
*/
|
|
35
|
+
function getNonce(options) {
|
|
36
|
+
return (0, nonce_1.getNonce)(options);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generate deterministic random number(s). Optional extraParams [A, B, ...] are included in the HMAC message.
|
|
40
|
+
*/
|
|
41
|
+
function generateRandomNumber(serverSeed, clientSeed, nonce, extraParams, options) {
|
|
42
|
+
return (0, verify_1.generateRandomNumber)(serverSeed, clientSeed, nonce, extraParams, options);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify fairness: recompute result and check server seed hash.
|
|
46
|
+
*/
|
|
47
|
+
function verifyFairness(serverSeed, clientSeed, nonce, committedServerSeedHash, expectedResult, extraParams, options) {
|
|
48
|
+
return (0, verify_1.verifyFairness)(serverSeed, clientSeed, nonce, committedServerSeedHash, expectedResult, extraParams, options);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAcA,8CAEC;AAKD,sCAEC;AAKD,sCAEC;AAKD,4BAEC;AAKD,oDAcC;AAKD,wCAkBC;AA/ED,qCAAqC;AACrC,mCAAoD;AACpD,qCAGkB;AAGlB,oFAAoF;AACpF,IAAI,eAAe,GAAW,EAAE,CAAC;AAEjC;;GAEG;AACH,SAAgB,iBAAiB,CAAC,UAAkB;IAClD,OAAO,IAAA,kBAAS,EAAC,UAAU,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa;IAC3B,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,IAAY;IACxC,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,OAAoB;IAC3C,OAAO,IAAA,gBAAa,EAAC,OAAO,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAClC,UAAkB,EAClB,UAAkB,EAClB,KAA2B,EAC3B,WAAiC,EACjC,OAA6B;IAE7B,OAAO,IAAA,6BAAS,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,WAAW,EACX,OAAO,CACR,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAC5B,UAAkB,EAClB,UAAkB,EAClB,KAA2B,EAC3B,uBAA+B,EAC/B,cAAiC,EACjC,WAAiC,EACjC,OAA6B;IAE7B,OAAO,IAAA,uBAAU,EACf,UAAU,EACV,UAAU,EACV,KAAK,EACL,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,OAAO,CACR,CAAC;AACJ,CAAC"}
|
package/dist/nonce.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NonceSource } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the numeric nonce from the given nonce source.
|
|
4
|
+
* Core module only uses the number; no HTTP. Use block-fetchers for EOS/BSC RPC.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getNonce(options: NonceSource): number;
|
|
7
|
+
//# sourceMappingURL=nonce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nonce.d.ts","sourceRoot":"","sources":["../src/nonce.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAarD"}
|
package/dist/nonce.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getNonce = getNonce;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the numeric nonce from the given nonce source.
|
|
6
|
+
* Core module only uses the number; no HTTP. Use block-fetchers for EOS/BSC RPC.
|
|
7
|
+
*/
|
|
8
|
+
function getNonce(options) {
|
|
9
|
+
switch (options.type) {
|
|
10
|
+
case "custom":
|
|
11
|
+
return options.value;
|
|
12
|
+
case "eos":
|
|
13
|
+
return options.blockHeight;
|
|
14
|
+
case "bsc":
|
|
15
|
+
return options.blockHeight;
|
|
16
|
+
default: {
|
|
17
|
+
const _ = options;
|
|
18
|
+
throw new Error("Invalid nonce source");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=nonce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nonce.js","sourceRoot":"","sources":["../src/nonce.ts"],"names":[],"mappings":";;AAMA,4BAaC;AAjBD;;;GAGG;AACH,SAAgB,QAAQ,CAAC,OAAoB;IAC3C,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,OAAO,CAAC,KAAK,CAAC;QACvB,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,WAAW,CAAC;QAC7B,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,WAAW,CAAC;QAC7B,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,CAAC,GAAU,OAAO,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nonce source: custom number, EOS block height, or BSC block height.
|
|
3
|
+
*/
|
|
4
|
+
export type NonceSource = {
|
|
5
|
+
type: "custom";
|
|
6
|
+
value: number;
|
|
7
|
+
} | {
|
|
8
|
+
type: "eos";
|
|
9
|
+
blockHeight: number;
|
|
10
|
+
} | {
|
|
11
|
+
type: "bsc";
|
|
12
|
+
blockHeight: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Result of verifyFairness().
|
|
16
|
+
*/
|
|
17
|
+
export interface VerifyResult {
|
|
18
|
+
/** Whether the recomputed result matches the expected result. */
|
|
19
|
+
resultMatches: boolean;
|
|
20
|
+
/** Whether the server seed hash matches the committed hash. */
|
|
21
|
+
serverSeedHashMatches: boolean;
|
|
22
|
+
/** Whether both checks passed (fair). */
|
|
23
|
+
isFair: boolean;
|
|
24
|
+
/** Recomputed result for debugging. */
|
|
25
|
+
computedResult?: number | number[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for generating random number(s).
|
|
29
|
+
*/
|
|
30
|
+
export interface RandomNumberOptions {
|
|
31
|
+
/** Minimum value (inclusive). Default 0. */
|
|
32
|
+
min?: number;
|
|
33
|
+
/** Maximum value (inclusive). Default 1. */
|
|
34
|
+
max?: number;
|
|
35
|
+
/** Number of values to generate. Default 1. */
|
|
36
|
+
count?: number;
|
|
37
|
+
/** If true, return integers; otherwise floats in [min, max]. Default true when min/max are integers. */
|
|
38
|
+
integer?: boolean;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;IACvB,+DAA+D;IAC/D,qBAAqB,EAAE,OAAO,CAAC;IAC/B,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wGAAwG;IACxG,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { VerifyResult, RandomNumberOptions } from "./types";
|
|
2
|
+
import type { NonceSource } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Generate deterministic random number(s) from server seed, client seed, nonce, and optional extra params.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateRandomNumber(serverSeed: string, clientSeed: string, nonce: NonceSource | number, extraParams?: (string | number)[], options?: RandomNumberOptions): number | number[];
|
|
7
|
+
/**
|
|
8
|
+
* Verify fairness: check server seed hash and recompute result.
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyFairness(serverSeed: string, clientSeed: string, nonce: NonceSource | number, committedServerSeedHash: string, expectedResult: number | number[], extraParams?: (string | number)[], options?: RandomNumberOptions): VerifyResult;
|
|
11
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAgC3C;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACjC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,GAAG,MAAM,EAAE,CAenB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,uBAAuB,EAAE,MAAM,EAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,EACjC,WAAW,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACjC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CA8Bd"}
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRandomNumber = generateRandomNumber;
|
|
4
|
+
exports.verifyFairness = verifyFairness;
|
|
5
|
+
const crypto_1 = require("./crypto");
|
|
6
|
+
const nonce_1 = require("./nonce");
|
|
7
|
+
/**
|
|
8
|
+
* Build the HMAC message: clientSeed:nonce[:extraParams...]
|
|
9
|
+
*/
|
|
10
|
+
function buildMessage(clientSeed, nonceValue, extraParams) {
|
|
11
|
+
const parts = [clientSeed, String(nonceValue)];
|
|
12
|
+
if (extraParams?.length) {
|
|
13
|
+
parts.push(...extraParams.map(String));
|
|
14
|
+
}
|
|
15
|
+
return parts.join(":");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Scale float in [0,1] to [min, max]. If integer, round to integer in range.
|
|
19
|
+
*/
|
|
20
|
+
function scaleToRange(float, min, max, integer) {
|
|
21
|
+
if (integer) {
|
|
22
|
+
return min + Math.floor(float * (max - min + 1));
|
|
23
|
+
}
|
|
24
|
+
return min + float * (max - min);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate deterministic random number(s) from server seed, client seed, nonce, and optional extra params.
|
|
28
|
+
*/
|
|
29
|
+
function generateRandomNumber(serverSeed, clientSeed, nonce, extraParams, options) {
|
|
30
|
+
const nonceValue = typeof nonce === "number" ? nonce : (0, nonce_1.getNonce)(nonce);
|
|
31
|
+
const message = buildMessage(clientSeed, nonceValue, extraParams);
|
|
32
|
+
const bytes = (0, crypto_1.hmacSha256Bytes)(serverSeed, message);
|
|
33
|
+
const min = options?.min ?? 0;
|
|
34
|
+
const max = options?.max ?? 1;
|
|
35
|
+
const count = options?.count ?? 1;
|
|
36
|
+
const integer = options?.integer ?? (Number.isInteger(min) && Number.isInteger(max));
|
|
37
|
+
const floats = (0, crypto_1.bytesToFloats)(bytes, count);
|
|
38
|
+
const scaled = floats.map((f) => scaleToRange(f, min, max, integer));
|
|
39
|
+
return count === 1 ? scaled[0] : scaled;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Verify fairness: check server seed hash and recompute result.
|
|
43
|
+
*/
|
|
44
|
+
function verifyFairness(serverSeed, clientSeed, nonce, committedServerSeedHash, expectedResult, extraParams, options) {
|
|
45
|
+
const computedHash = (0, crypto_1.sha256Hex)(serverSeed);
|
|
46
|
+
const serverSeedHashMatches = computedHash === committedServerSeedHash;
|
|
47
|
+
const nonceValue = typeof nonce === "number" ? nonce : (0, nonce_1.getNonce)(nonce);
|
|
48
|
+
const computedResult = generateRandomNumber(serverSeed, clientSeed, nonceValue, extraParams, options);
|
|
49
|
+
const computedArr = Array.isArray(computedResult)
|
|
50
|
+
? computedResult
|
|
51
|
+
: [computedResult];
|
|
52
|
+
const expectedArr = Array.isArray(expectedResult)
|
|
53
|
+
? expectedResult
|
|
54
|
+
: [expectedResult];
|
|
55
|
+
const resultMatches = computedArr.length === expectedArr.length &&
|
|
56
|
+
computedArr.every((v, i) => v === expectedArr[i]);
|
|
57
|
+
return {
|
|
58
|
+
resultMatches,
|
|
59
|
+
serverSeedHashMatches,
|
|
60
|
+
isFair: resultMatches && serverSeedHashMatches,
|
|
61
|
+
computedResult,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@casino-core/probably-fair",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Provably fair gaming module for casino platforms – server/client seeds, configurable nonce, verification",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./block-fetchers": {
|
|
14
|
+
"import": "./dist/block-fetchers/index.js",
|
|
15
|
+
"require": "./dist/block-fetchers/index.js",
|
|
16
|
+
"types": "./dist/block-fetchers/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/huberco/provably-fair.git"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"provably-fair",
|
|
37
|
+
"casino",
|
|
38
|
+
"gaming",
|
|
39
|
+
"server-seed",
|
|
40
|
+
"client-seed",
|
|
41
|
+
"nonce",
|
|
42
|
+
"verification"
|
|
43
|
+
],
|
|
44
|
+
"author": "",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=16"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/jest": "^29.5.12",
|
|
51
|
+
"@types/node": "^20.11.0",
|
|
52
|
+
"jest": "^29.7.0",
|
|
53
|
+
"ts-jest": "^29.1.2",
|
|
54
|
+
"typescript": "^5.3.3"
|
|
55
|
+
}
|
|
56
|
+
}
|